System, method and article of manufacture for interface constructs in a programming language capable of programming hardware architetures

ABSTRACT

A system, method and article of manufacture are provided for using a versatile interface. First computer code is written in a first programming language. Included in the first computer code is reference to second computer code in a second programming language. The second computer code is simulated for use during the execution of the first computer code in the first programming language.

FIELD OF THE INVENTION

[0001] The present invention relates to programmable hardwarearchitectures and more particularly to programming field programmablegate arrays (FPGA's).

BACKGROUND OF THE INVENTION

[0002] It is well known that software-controlled machines provide greatflexibility in that they can be adapted to many different desiredpurposes by the use of suitable software. As well as being used in thefamiliar general purpose computers, software-controlled processors arenow used in many products such as cars, telephones and other domesticproducts, where they are known as embedded systems.

[0003] However, for a given function, a software-controlled processor isusually slower than hardware dedicated to that function. A way ofovercoming this problem is to use a special software-controlledprocessor such as a RISC processor which can be made to function morequickly for limited purposes by having its parameters (for instancesize, instruction set etc.) tailored to the desired functionality.

[0004] Where hardware is used, though, although it increases the speedof operation, it lacks flexibility and, for instance, although it may besuitable for the task for which it was designed it may not be suitablefor a modified version of that task which is desired later. It is nowpossible to form the hardware on reconfigurable logic circuits, such asField Programmable Gate Arrays (FPGA's) which are logic circuits whichcan be repeatedly reconfigured in different ways. Thus they provide thespeed advantages of dedicated hardware, with some degree of flexibilityfor later updating or multiple functionality.

[0005] In general, though, it can be seen that designers face a problemin finding the right balance between speed and generality. They canbuild versatile chips which will be software controlled and thus performmany different functions relatively slowly, or they can deviseapplication-specific chips that do only a limited set of tasks but dothem much more quickly.

[0006] It should also be noted that programming for hardware may bequite challenging, thus leading to the need for languages that allowprogrammers to think abstractly while maintaining quality results.

SUMMARY OF THE INVENTION

[0007] A system, method and article of manufacture are provided forusing a versatile interface. First computer code is written in a firstprogramming language. Included in the first computer code is referenceto second computer code in a second programming language. The secondcomputer code is simulated for use during the execution of the firstcomputer code in the first programming language.

[0008] In an aspect of the present invention, the second computer codemay be simulated by a first simulator module. In such an aspect, thefirst simulator module may interface a second simulator module. As afurther option, the first simulator module may interface the secondsimulator module via a plug-in module. In another aspect of the presentinvention, the reference to the second computer code may include apredetermined command in the first computer code. In a further aspect,the second computer code may simulate an external device. In evenanother aspect, the first programming language may include Handel-C. Inyet a further aspect, the second programming language may be either EDIFor VDHL.

BRIEF DESCRIPTION OF THE DRAWINGS

[0009] The invention may be better understood when consideration isgiven to the following detailed description thereof. Such descriptionmakes reference to the annexed drawings wherein:

[0010]FIG. 1 is a schematic diagram of a hardware implementation of oneembodiment of the present invention;

[0011]FIG. 2 illustrates a design flow overview, in accordance with oneembodiment of the present invention;

[0012]FIG. 3 illustrates the Handel-C development environment, inaccordance with one embodiment of the present invention;

[0013]FIG. 4 illustrates a graphical user interface shown if one startsthe program with an empty workspace;

[0014]FIG. 5 illustrates a graphical user interface used to create aproject, in accordance with one embodiment of the present invention;

[0015]FIG. 6 illustrates the various types of new projects, inaccordance with one embodiment of the present invention;

[0016]FIG. 7 illustrates a breakpoint, in accordance with one embodimentof the present invention;

[0017]FIG. 8 illustrates a project settings interface, in accordancewith one embodiment of the present invention;

[0018]FIGS. 9A, 9B, and 9C illustrate available settings;

[0019]FIG. 10 illustrates a configurations graphical user interface, inaccordance with one embodiment of the present invention;

[0020]FIG. 11 illustrates a file view interface, in accordance with oneembodiment of the present invention;

[0021]FIG. 12 illustrates a file properties, in accordance with oneembodiment of the present invention;

[0022]FIG. 13 illustrates a workspace interface and the associatedicons, in accordance with one embodiment of the present invention;

[0023]FIG. 14 illustrates a version test interface, in accordance withone embodiment of the present invention;

[0024]FIG. 15 illustrate a browse and associated results interface, inaccordance with one embodiment of the present invention;

[0025]FIGS. 16A and 16B illustrate browsing commands, in accordance withone embodiment of the present invention;

[0026]FIG. 17 is a table of editing commands, in accordance with oneembodiment of the present invention;

[0027]FIG. 18 is a table of regular expressions, in accordance with oneembodiment of the present invention;

[0028]FIG. 19 is a table of various project files, in accordance withone embodiment of the present invention;

[0029]FIG. 20 illustrates a GUI for customizing the interface, inaccordance with one embodiment of the present invention;

[0030]FIG. 20A illustrates a method for compiling a computer program forprogramming a hardware device;

[0031]FIG. 21 illustrates a build interface, in accordance with oneembodiment of the present invention;

[0032]FIG. 22 illustrates table showing a build menu, in accordance withone embodiment of the present invention;

[0033]FIG. 22A illustrates a method for debugging a computer program, inaccordance with one embodiment of the present invention;

[0034]FIGS. 23A and 23B illustrate the various commands associated withthe debug menu, in accordance with one embodiment of the presentinvention;

[0035]FIG. 24 illustrates a table showing the various windows associatedwith the debugger interface, in accordance with one embodiment of thepresent invention;

[0036]FIG. 25 illustrates a variables window interface, in accordancewith one embodiment of the present invention;

[0037]FIG. 26 illustrates the current positioning function blib, and therelated call stack window;

[0038]FIG. 27 illustrates a threads window interface, in accordance withone embodiment of the present invention;

[0039]FIG. 28 illustrates a variables window interface, in accordancewith one embodiment of the present invention;

[0040]FIG. 29 illustrates a breakpoints window interface, in accordancewith one embodiment of the present invention;

[0041]FIGS. 30 and 31 illustrate a table showing various differencesbetween Handel-C and the conventional C programming language, inaccordance with one embodiment of the present invention;

[0042]FIG. 32 illustrates a table of types, type operators and objects,in accordance with one embodiment of the present invention;

[0043]FIG. 33 illustrates a table of statements, in accordance with oneembodiment of the present invention;

[0044]FIG. 34 illustrates a table of expressions, in accordance with oneembodiment of the present invention;

[0045]FIG. 35 illustrates a net list reader settings display, inaccordance with one embodiment of the present invention;

[0046]FIGS. 36 and 37 illustrate a tool settings display, in accordancewith one embodiment of the present invention;

[0047]FIG. 38 illustrates the wires that would be produced whenspecifying floating wire names, in accordance with one embodiment of thepresent invention;

[0048]FIG. 39 illustrates an interface between Handel-C and VHDL forsimulation, in accordance with one embodiment of the present invention;

[0049]FIGS. 40A and 40B illustrate a table of possible specifications,in accordance with one embodiment of the present invention;

[0050]FIG. 41 illustrates the use of various VHDL files, in accordancewith one embodiment of the present invention;

[0051]FIG. 41A illustrates a method for equipping a simulator withplug-ins;

[0052]FIGS. 42A and 42B illustrate various function calls and thevarious uses thereof, in accordance with one embodiment of the presentinvention;

[0053]FIG. 43 illustrates a plurality of possible values and meaningsassociated with libraries of the present invention;

[0054]FIG. 44 shows how the synchronization works when single-steppingthe two projects in simulation;

[0055]FIG. 44A illustrates a pair of simulators, in accordance with oneembodiment of the present invention;

[0056]FIG. 44B illustrates a cosimulation arrangement includingprocesses and DLLs;

[0057]FIG. 44C illustrates an example of a simulator reengagement, inaccordance with one embodiment of the present invention;

[0058]FIG. 44D illustrates a schematic of exemplary cosimulationarchitecture;

[0059]FIGS. 45A and 45B summarize the options available on the compiler;

[0060]FIGS. 46A and 46B illustrate various commands and debugs, inaccordance with one embodiment of the present invention;

[0061]FIGS. 47A through 47C illustrate various icons that may beutilized, in accordance with one embodiment of the present invention;

[0062]FIG. 48 illustrates the various raw file bit numbers and thecorresponding color bits;

[0063]FIG. 49 illustrates the manner in which branches that completeearly are forced to wait for the slowest branch before continuing;

[0064]FIG. 50 illustrates the link between parallel branches, inaccordance with one embodiment of the present invention;

[0065]FIG. 51 illustrates the scope of variables, in accordance with oneembodiment of the present invention

[0066]FIGS. 52, 53 and 54 illustrate a table of operators, statements,and macros respectively, along with alternate meanings thereof;

[0067]FIG. 55 illustrates a compiler, in accordance with one embodimentof the present invention;

[0068]FIG. 56 illustrates the various specifications for the interfacesof the present invention;

[0069]FIG. 57 illustrates a table showing the ROM entries, in accordancewith one embodiment of the present invention;

[0070]FIG. 57A illustrates a method for using a dynamic object in aprogramming language;

[0071]FIG. 57A-1 illustrates a method for using extensions to executecommands in parallel;

[0072]FIG. 57A-2 illustrates a method for parameterized expressions, inaccordance with various embodiments of the present invention;

[0073]FIGS. 58A and 58B illustrate a summary of statement timings, inaccordance with one embodiment of the present invention;

[0074]FIG. 59 illustrates various I/O based on clock cycles, inaccordance with one embodiment of the present invention;

[0075]FIG. 60 illustrates a table showing the various locations, inaccordance with one embodiment of the present invention;

[0076]FIG. 61 illustrates the various family names, in accordance withone embodiment of the present invention;

[0077]FIG. 62 illustrates a timing diagram showing a signal, inaccordance with one embodiment of the present invention;

[0078]FIG. 63 illustrates a timing diagram showing a SSRAM read andwrite, in accordance with one embodiment of the present invention;

[0079]FIG. 64 illustrates a timing diagram showing a SSRAM read cycleusing generated RAMCLK, in accordance with one embodiment of the presentinvention;

[0080]FIG. 65 illustrates a timing diagram showing read-cycle from aflow-through SSRAM within a Handel-C design, in accordance with oneembodiment of the present invention;

[0081]FIG. 66 illustrates a timing diagram showing complete write cycle,in accordance with one embodiment of the present invention;

[0082]FIG. 67 illustrates a timing diagram showing complete read cycle,in accordance with one embodiment of the present invention;

[0083]FIG. 68 illustrates a timing diagram showing complete cycle, inaccordance with one embodiment of the present invention;

[0084]FIG. 69 illustrates a timing diagram showing a cycle for a writeto external RAM, in accordance with one embodiment of the presentinvention;

[0085]FIG. 70 illustrates a timing diagram showing a cycle for a readfrom external RAM, in accordance with one embodiment of the presentinvention;

[0086]FIG. 71 illustrates a timing diagram showing a cycle for a writeto external RAM, in accordance with one embodiment of the presentinvention;

[0087]FIG. 72 illustrates a timing diagram showing a cycle for a readfrom external RAM, in accordance with one embodiment of the presentinvention;

[0088]FIG. 73 illustrates a timing diagram showing a cycle for a writeto external RAM, in accordance with one embodiment of the presentinvention;

[0089]FIG. 74 illustrates a timing diagram showing a cycle for a readfrom external RAM, in accordance with one embodiment of the presentinvention;

[0090]FIG. 75 is a table of pre-defined interface sorts, in accordancewith one embodiment of the present invention;

[0091]FIG. 76 illustrates a timing diagram, in accordance with oneembodiment of the present invention;

[0092]FIG. 76A is a flowchart showing a method for providing a versatileinterface;

[0093]FIG. 77 illustrates the manner in which an interface is specified,in accordance with one embodiment of the present invention;

[0094]FIGS. 78A through 78C illustrate a table showing the specificationof various keywords, in accordance with one embodiment of the presentinvention;

[0095]FIG. 78D illustrates the manner in which an pin outs arespecified, in accordance with one embodiment of the present invention;

[0096]FIG. 79 illustrates the various signals employed by the presentinvention;

[0097]FIG. 80 illustrates a read waveform representative of a cycle, inaccordance with one embodiment of the present invention;

[0098]FIG. 81 illustrates a waveform representative of a write cycle, inaccordance with one embodiment of the present invention;

[0099]FIG. 82 illustrates a table that lists the most common types thatmay be associated with a variable, in accordance with one embodiment ofthe present invention;

[0100]FIG. 83 illustrates a table that lists all prefixes to the abovetypes for different architectural object types, in accordance with oneembodiment of the present invention;

[0101]FIG. 84 illustrates a table that lists all statements in theHandel-C language, in accordance with one embodiment of the presentinvention;

[0102]FIGS. 85A and 85B illustrate a table that lists all operators inthe Handel-C language, in accordance with one embodiment of the presentinvention;

[0103]FIGS. 86A through 86E illustrate a table that lists keywords, inaccordance with one embodiment of the present invention;

[0104]FIG. 87A illustrates escape codes and their associated meanings,in accordance with one embodiment of the present invention;

[0105]FIG. 87B illustrates a method for distributing cores, inaccordance with one embodiment of the present invention;

[0106]FIG. 87C illustrates a method for using a library map during thedesign of cores, in accordance with one embodiment of the presentinvention;

[0107]FIG. 87D illustrates a method for providing polymorphism usingpointers, in accordance with one embodiment of the present invention;

[0108]FIG. 87E illustrates a method for generating libraries utilizingpre-compiler macros, in accordance with one embodiment of the presentinvention;

[0109]FIG. 87F illustrates a method for mimicking object orientedprogramming utilizing pointers in a programmable hardware architecture,in accordance with one embodiment of the present invention;

[0110]FIG. 88 illustrates an application program interface, inaccordance with one embodiment of the present invention, in accordancewith one embodiment of the present invention;

[0111]FIG. 89 illustrates that the physical layer is divided into afurther two sections, in accordance with one embodiment of the presentinvention;

[0112]FIG. 90 is a schematic diagram of the application layer, physicallayer, and user domain, in accordance with one embodiment of the presentinvention;

[0113]FIG. 91 shows a typical execution flow for a function, inaccordance with one embodiment of the present invention;

[0114]FIG. 92 shows a typical address packet, in accordance with oneembodiment of the present invention;

[0115]FIG. 93 illustrates a Trace and Pattern window, in accordance withone embodiment of the present invention; and

[0116]FIG. 94 illustrates several toolbar icons and their functions, inaccordance with one embodiment of the present invention.

DETAILED DESCRIPTION OF THE PREFERRED EMBODIMENTS

[0117] A preferred embodiment of a system in accordance with the presentinvention is preferably practiced in the context of a personal computersuch as an IBM compatible personal computer, Apple Macintosh computer orUNIX based workstation. A representative hardware environment isdepicted in FIG. 1, which illustrates a typical hardware configurationof a workstation in accordance with a preferred embodiment having acentral processing unit 110, such as a microprocessor, and a number ofother units interconnected via a system bus 112.

[0118] The workstation shown in FIG. 1 includes a Random Access Memory(RAM) 114, Read Only Memory (ROM) 116, an I/O adapter 118 for connectingperipheral devices such as disk storage units 120 to the bus 112, a userinterface adapter 122 for connecting a keyboard 124, a mouse 126, aspeaker 128, a microphone 132, and/or other user interface devices suchas a touch screen (not shown) to the bus 112, communication adapter 134for connecting the workstation to a communication network (e.g., a dataprocessing network) and a display adapter 136 for connecting the bus 112to a display device 138.

[0119] The workstation typically has resident thereon an operatingsystem such as the Microsoft Windows NT or Windows/95 Operating System(OS), the IBM OS/2 operating system, the MAC OS, or UNIX operatingsystem. Those skilled in the art may appreciate that the presentinvention may also be implemented on platforms and operating systemsother than those mentioned.

[0120] In one embodiment, the hardware environment of FIG. 1 mayinclude, at least in part, a field programmable gate array (FPGA)device. For example, the central processing unit 110 may be replaced orsupplemented with an FPGA. Use of such device provides flexibility infunctionality, while maintaining high processing speeds.

[0121] Examples of such FPGA devices include the XC2000™ and XC3000™families of FPGA devices introduced by Xilinx, Inc. of San Jose, Calif.The architectures of these devices are exemplified in U.S. Pat. Nos.4,642,487; 4,706,216; 4,713,557; and 4,758,985; each of which isoriginally assigned to Xilinx, Inc. and which are herein incorporated byreference for all purposes. It should be noted, however, that FPGA's ofany type may be employed in the context of the present invention.

[0122] An FPGA device can be characterized as an integrated circuit thathas four major features as follows.

[0123] (1) A user-accessible, configuration-defining memory means, suchas SRAM, PROM, EPROM, EEPROM, anti-fused, fused, or other, is providedin the FPGA device so as to be at least once-programmable by deviceusers for defining user-provided configuration instructions. StaticRandom Access Memory or SRAM is of course, a form of reprogrammablememory that can he differently programmed many times. ElectricallyErasable and reProgrammable ROM or EEPROM is an example of nonvolatilereprogrammable memory. The configuration-defining memory of an FPGAdevice can be formed of mixture of different kinds of memory elements ifdesired (e.g., SRAM and EEPROM) although this is not a popular approach.

[0124] (2) Input/Output Blocks (IOB's) are provided for interconnectingother internal circuit components of the FPGA device with externalcircuitry. The IOB's' may have fixed configurations or they may beconfigurable in accordance with user-provided configuration instructionsstored in the configuration-defining memory means.

[0125] (3) Configurable Logic Blocks (CLB's) are provided for carryingout user-programmed logic functions as defined by user-providedconfiguration instructions stored in the configuration-defining memorymeans.

[0126] Typically, each of the many CLB's of an FPGA has at least onelookup table (LUT) that is user-configurable to define any desired truthtable,—to the extent allowed by the address space of the LUT. Each CLBmay have other resources such as LUT input signal pre-processingresources and LUT output signal post-processing resources. Although theterm ‘CLB’ was adopted by early pioneers of FPGA technology, it is notuncommon to see other names being given to the repeated portion of theFPGA that carries out user-programmed logic functions. The term, ‘LAB’is used for example in U.S. Pat. No. 5,260,611 to refer to a repeatedunit having a 4-input LUT.

[0127] (4) An interconnect network is provided for carrying signaltraffic within the FPGA device between various CLB's and/or betweenvarious IOB's and/or between various IOB's and CLB's. At least part ofthe interconnect network is typically configurable so as to allow forprogrammably-defined routing of signals between various CLB's and/orIOB's in accordance with user-defined routing instructions stored in theconfiguration-defining memory means.

[0128] In some instances, FPGA devices may additionally include embeddedvolatile memory for serving as scratchpad memory for the CLB's or asFIFO or LIFO circuitry. The embedded volatile memory may be fairlysizable and can have 1 million or more storage bits in addition to thestorage bits of the device's configuration memory.

[0129] Modern FPGA's tend to be fairly complex. They typically offer alarge spectrum of user-configurable options with respect to how each ofmany CLB's should be configured, how each of many interconnect resourcesshould be configured, and/or how each of many IOB's should beconfigured. This means that there can be thousands or millions ofconfigurable bits that may need to be individually set or cleared duringconfiguration of each FPGA device.

[0130] Rather than determining with pencil and paper how each of theconfigurable resources of an FPGA device should be programmed, it iscommon practice to employ a computer and appropriate FPGA-configuringsoftware to automatically generate the configuration instruction signalsthat may be supplied to, and that may ultimately cause an unprogrammedFPGA to implement a specific design. (The configuration instructionsignals may also define an initial state for the implemented design,that is, initial set and reset states for embedded flip flops and/orembedded scratchpad memory cells.)

[0131] The number of logic bits that are used for defining theconfiguration instructions of a given FPGA device tends to be fairlylarge (e.g., 1 Megabits or more) and usually grows with the size andcomplexity of the target FPGA. Time spent in loading configurationinstructions and verifying that the instructions have been correctlyloaded can become significant, particularly when such loading is carriedout in the field.

[0132] For many reasons, it is often desirable to have in-systemreprogramming capabilities so that reconfiguration of FPGA's can becarried out in the field.

[0133] FPGA devices that have configuration memories of thereprogrammable kind are, at least in theory, ‘in-system programmable’(ISP). This means no more than that a possibility exists for changingthe configuration instructions within the FPGA device while the FPGAdevice is ‘in-system’ because the configuration memory is inherentlyreprogrammable. The term, ‘in-system’ as used herein indicates that theFPGA device remains connected to an application-specific printed circuitboard or to another form of end-use system during reprogramming. Theend-use system is of course, one which contains the FPGA device and forwhich the FPGA device is to be at least once configured to operatewithin in accordance with predefined, end-use or ‘in the field’application specifications.

[0134] The possibility of reconfiguring such inherently reprogrammableFPGA's does not mean that configuration changes can always be made withany end-use system. Nor does it mean that, where in-system reprogrammingis possible, that reconfiguration of the FPGA can be made in timelyfashion or convenient fashion from the perspective of the end-use systemor its users. (Users of the end-use system can be located either locallyor remotely relative to the end-use system.)

[0135] Although there may be many instances in which it is desirable toalter a pre-existing configuration of an ‘in the field’ FPGA (with thealteration commands coming either from a remote site or from the localsite of the FPGA), there are certain practical considerations that maymake such in-system reprogrammability of FPGA's more difficult thanfirst apparent (that is, when conventional techniques for FPGAreconfiguration are followed).

[0136] A popular class of FPGA integrated circuits (IC's) relies onvolatile memory technologies such as SRAM (static random access memory)for implementing on-chip configuration memory cells. The popularity ofsuch volatile memory technologies is owed primarily to the inherentreprogrammability of the memory over a device lifetime that can includean essentially unlimited number of reprogramming cycles.

[0137] There is a price to be paid for these advantageous features,however. The price is the inherent volatility of the configuration dataas stored in the FPGA device. Each time power to the FPGA device is shutoff, the volatile configuration memory cells lose their configurationdata. Other events may also cause corruption or loss of data fromvolatile memory cells within the FPGA device.

[0138] Some form of configuration restoration means is needed to restorethe lost data when power is shut off and then re-applied to the FPGA orwhen another like event calls for configuration restoration (e.g.,corruption of state data within scratchpad memory).

[0139] The configuration restoration means can take many forms. If theFPGA device resides in a relatively large system that has a magnetic oroptical or opto-magnetic form of nonvolatile memory (e.g., a hardmagnetic disk)—and the latency of powering up such a optical/magneticdevice and/or of loading configuration instructions from such anoptical/magnetic form of nonvolatile memory can be tolerated—then theoptical/magnetic memory device can be used as a nonvolatileconfiguration restoration means that redundantly stores theconfiguration data and is used to reload the same into the system's FPGAdevice(s) during power-up operations (and/or other restoration cycles).

[0140] On the other hand, if the FPGA device(s) resides in a relativelysmall system that does not have such optical/magnetic devices, and/or ifthe latency of loading configuration memory data from such anoptical/magnetic device is not tolerable, then a smaller and/or fasterconfiguration restoration means may be called for.

[0141] Many end-use systems such as cable-TV set tops, satellitereceiver boxes, and communications switching boxes are constrained byprespecified design limitations on physical size and/or power-up timingand/or security provisions and/or other provisions such that they cannotrely on magnetic or optical technologies (or on network/satellitedownloads) for performing configuration restoration. Their designsinstead call for a relatively small and fast acting, non-volatile memorydevice (such as a securely-packaged EPROM IC), for performing theconfiguration restoration function. The small/fast device is expected tosatisfy application-specific criteria such as: (1) being securelyretained within the end-use system; (2) being able to store FPGAconfiguration data during prolonged power outage periods; and (3) beingable to quickly and automatically re-load the configuration instructionsback into the volatile configuration memory (SRAM) of the FPGA deviceeach time power is turned back on or another event calls forconfiguration restoration

[0142] The term ‘CROP device’ may be used herein to refer in a generalway to this form of compact, nonvolatile, and fast-acting device thatperforms ‘Configuration-Restoring On Power-up’ services for anassociated FPGA device.

[0143] Unlike its supported, volatilely reprogrammable FPGA device, thecorresponding CROP device is not volatile, and it is generally not‘in-system programmable’. Instead, the CROP device is generally of acompletely nonprogrammable type'such as exemplified by mask-programmedROM IC's or by once-only programmable, fuse-based PROM IC's. Examples ofsuch CROP devices include a product family that the Xilinx companyprovides under the designation ‘Serial Configuration PROMs’ and underthe trade name, XC1700D.TM. These serial CROP devices employ one-timeprogrammable PROM (Programmable Read Only Memory) cells for storingconfiguration instructions in nonvolatile fashion.

[0144] A preferred embodiment is written using Handel-C. Handel-C is aprogramming language marketed by Celoxica Limited. Handel-C is aprogramming language that enables a software or hardware engineer totarget directly FPGAs (Field Programmable Gate Arrays) in a similarfashion to classical microprocessor cross-compiler development tools,without recourse to a Hardware Description Language. This allows thedesigner to directly realize the raw real-time computing capability ofthe FPGA.

[0145] Handel-C allows one to use a high-level language to programFPGAs. It makes it easy to implement complex algorithms by using asoftware-based language rather than a hardware architecture-basedlanguage. One can use all the power of reconfigurable computing in FPGAswithout needing to know the details of the FPGAs themselves. A programmay be written in Handel-C to generate all required state machines,while one can specify storage requirements down to the bit level. Aclock and clock speed may be assigned for working with the simple butexplicit model of one clock cycle per assignment. A Handel-C macrolibrary may be used for bit manipulation and arithmetic operations. Theprogram may be compiled and then simulated and debugged on a PC similarto that in FIG. 1. This may be done while stepping through single ormultiple clock cycles.

[0146] When one has designed their chip, the code can be compileddirectly to a netlist, ready to be used by manufacturers' place androute tools for a variety of different chips.

[0147] As such, one can design hardware quickly because he or she canwrite high-level code instead of using a hardware description language.Handel-C optimizes code, and uses efficient algorithms to generate thelogic hardware from the program. Because of the speed of development andthe ease of maintaining well-commented high-level code, it allows one touse reconfigurable computing easily and efficiently.

[0148] Handel-C has the tight relationship between code and hardwaregeneration required by hardware engineers, with the advantages ofhigh-level language abstraction. Further features include:

[0149] C-like language allows one to program quickly

[0150] Architecture specifiers allow one to define RAMs, ROMs, buses andinterfaces.

[0151] Parallelism allows one to optimize use of the FPGA

[0152] Close correspondence between the program and the hardware

[0153] Easy to understand timing model

[0154] Full simulation of owner hardware on the PC

[0155] Display the contents of registers every clock cycle during debug

[0156] Rapid prototyping

[0157] Convert existing C programs to hardware

[0158] Works with manufacturers' existing tools

[0159] Rapid reconfiguration

[0160] Logic estimation tool highlights code inefficiencies in coloredWeb pages

[0161] Device-independent programs

[0162] Generates EDIFand XNF formats (and XBLOX macros)

[0163] Handel-C is thus designed to enable the compilation of programsinto synchronous hardware; it is aimed at compiling high levelalgorithms directly into gate level hardware. The Handel-C syntax isbased on that of conventional C so programmers familiar withconventional C may recognize almost all the constructs in the Handel-Clanguage. Sequential programs can be written in Handel-C just as inconventional C but to gain the most benefit in performance from thetarget hardware its inherent parallelism may be exploited. Handel-Cincludes parallel constructs that provide the means for the programmerto exploit this benefit in his applications. The compiler compiles andoptimizes Handel-C source code into a file suitable for simulation or anet list which can be placed and routed on a real FPGA.

[0164] More information regarding the Handel-C programming language willnow be set forth. For further information, reference may be made to“EMBEDDED SOLUTIONS Handel-C Language Reference Manual: Version 3,”“EMBEDDED SOLUTIONS Handel-C User Manual: Version 3.0,” “EMBEDDEDSOLUTIONS Handel-C Interfacing to other language code blocks: Version3.0,” and “EMBEDDED SOLUTIONS Handel-C Preprocessor Reference Manual:Version 2.1,” each authored by Rachel Ganz, and published by EmbeddedSolutions Limited, and which are each incorporated herein by referencein their entirety.

[0165] The present description is divided in a plurality of sections setforth under the headings:

[0166] HANDEL-C COMPILER AND SIMULATOR

[0167] HANDEL-C LANGUAGE

[0168] PREPROCESSOR

[0169] FPGA-BASED CO-PROCESSOR API

[0170] FIXED AND FLOATING POINT LIBRARY

[0171] WAVEFORM ANALYSIS

Handel-C Compiler and Simulator

[0172] Conventions

[0173] A number of conventions are used throughout this description.These conventions are detailed below. Hexadecimal numbers appearthroughout this description. The convention used is that of prefixingthe number with ‘Ox’ in common with standard C syntax.

[0174] Sections of code or commands that one may type are given intypewriter font as follows:

[0175] “void main( );”

[0176] Information about a type of object one may specify is given initalics as follows:

[0177] “copy SourceFileName DestinationFileName”

[0178] Menu items appear in narrow bold text as follows:

[0179] “insert Project into Workspace”

[0180] Elements within a menu are separated from the menu name by a > soEdit>Find means the Find item in the Edit menu.

[0181] Introduction

[0182] Handel-C is a programming language designed to enable thecompilation of programs into synchronous hardware. The Handel-C compilerand simulator will now be described. The Handel-C language may bedescribed hereinafter in greater detail.

[0183] The present description contains:

[0184] Getting started

[0185] User interface overview

[0186] Compiler and simulator overview

[0187] Examples of compiler and simulator use

[0188] Notes on using Handel-C and porting C code to Handel-C

[0189] Description of interfacing with VHDL code

[0190] Guide to the API (Application Programmers Interface)

[0191] Descriptions of the bitmap to data conversion utilities used bythe

[0192] examples.

[0193] Overview

[0194] Design Flow Overview

[0195]FIG. 2 illustrates a design flow overview 200, in accordance withone embodiment of the present invention. The dotted lines 202 show theextra steps 204 required if one wishes to integrate Handel-C with VHDL.

[0196] Getting Started.

[0197] Introduction

[0198] The present section gives a brief description of how to use theHandel-C compiler and simulator.

[0199] The Handel-C Development Environment

[0200]FIG. 3 illustrates the Handel-C development environment 300, inaccordance with one embodiment of the present invention. The Handel-Cdevelopment environment is a standard Windows development environment.It is in four main parts. The windows and toolbars are standard Windowsdockable windows and customizable toolbars.

[0201] Expected Development Sequence

[0202] The normal development sequence for a single-chip project is asfollows:

[0203] 1. Create a new project.

[0204] 2. Configure the project.

[0205] 3. Add the empty source code files to the project.

[0206] 4. Create source code.

[0207] 5. Link to any required libraries.

[0208] 6. Set up the files for debug.

[0209] 7. Compile the project for debug.

[0210] 8. Debug the project.

[0211] 9. Compile the project for target chip.

[0212] 10. Export the target file to a place and route tool.

[0213] 11. Place and route.

[0214] There is not necessarily information on placing and routingwithin the Handel:C documentation. The steps are described below.

[0215] Invoking the Environment.

[0216] One starts Handel-C by doing one of:

[0217] selecting Start>Programs>Handel-C>Handel-C

[0218] double-clicking on an existing Handel-C workspace file (fileswith the extension .hw)

[0219] double-clicking the Handel-C icon

[0220]FIG. 4 illustrates a graphical user interface 400 shown if onestarts the program with an empty workspace.

[0221] Creating the Project

[0222]FIG. 5 illustrates a graphical user interface 500 used to create aproject, in accordance with one embodiment of the present invention.

[0223] Select New from the File menu.

[0224] Select the Project tab in the dialog that appears.

[0225] One may be asked for the name and location (pathname for thedirectory that it is stored in) for the project. One can look for adirectory by clicking the . . . button to the right of the Location box.

[0226] By default, a new workspace is created for the project in thesame directory as the project. Workspace files have .hw extensions.Project files have .hp extensions. When one starts a new project, onemay have to define its type. FIG. 6 illustrates the various types 600 ofnew projects, in accordance with one embodiment of the presentinvention.

[0227] Common pre-defined project types are supplied with Handel-C.

[0228] Select the appropriate project type from the types listed in theProject pane.

[0229] Click OK.

[0230] Configuring the Project

[0231] Once a person has created a project, one should configure itssettings. These settings define what type of chip is targeted, and howthe compiler, pre-processor and optimizer work. The default settings arecorrect for a new project that one wishes to debug.

[0232] Adding Files to the Project

[0233] Add a Handel-C source file to the new project. This may be onethat a person has already written, or a new, empty one

[0234] Creating a New File

[0235] Select File>New, and click the Source File tab.

[0236] Select whether it's a header file or a source file in theleft-hand pane.

[0237] Select the project the file should belong to from the drop-downlist of current projects.

[0238] Set the location (the directory path where the file is stored),either by typing the pathname in the box, or selecting a directory byclicking the . . . button.

[0239] The code editor window may open.

[0240] Adding an Existing File

[0241] Select Project>Add to Project>Files and browse the directory treefor the files one wishes to add.

[0242] One can add multiple files from a directory by selecting themall.

[0243] OR

[0244] Right-click the mouse on the project, and select Add Files toFolder from the shortcut menu.

[0245] Removing Files From a Project

[0246] One can remove files from a project by selecting the file in theworkspace window and pressing the Delete key or selecting Edit>Delete.This does not delete the file from the hard disk.

[0247] Opening an existing source code file does not add it to theproject. It may not be built or compiled. One may explicitly add filesto the project.

[0248] Writing Source Code

[0249] One may write Handel-C source code in the source code editor.Code is indented at the same level as the line above it and is syntaxhighlighted.

[0250] Having a file open in the source code editor does not mean thatit is part of the project. The only files that may be compiled and builtare those that may have been added to the project,

[0251] Setting Up for Debug

[0252] There are several methods of coding Handel-C to help one debug aproject.

[0253] They fall into two kinds:

[0254] Code which may automatically be discarded by the compiler if onedoes not compile a project for debug, e.g., the with {infile=“file”}directive

[0255] Code where one supplies alternatives to be compiled for debug andrelease or target compilations. In these cases, one can use the #ifdefDEBUG, #ifdef NDEBUG and #ifdef SIMULATE directives.

[0256] By default, DEBUG and SIMULATE may be defined if one compiles fordebug, and NDEBUG may be defined for all other compilations. Forexample:

[0257] .ifdef SIMULATE

[0258] sim_chan ? var; // Read from simulator

[0259] .else

[0260] HardwareMacroRead(var); // Real HW interface

[0261] .endif

[0262] Summary of coding techniques used for debug:

[0263] Substitute simulator channels for hardware interface channels

[0264] Use the assert directive to stop a compilation if a condition isuntrue.

[0265] Substitute file input for external channel input

[0266] Export the contents of variables into files

[0267] Build and Compile for Debug

[0268] Debug is the default compilation target. It is unlikely that onewould need to make any changes to the project settings at this stage.The compiler creates a file which is in turn compiled into native PCcode using Microsoft Visual C++. This creates the chip simulation.

[0269] To build and compile the project, select Build from the Buildmenu. Messages from the compiler may appear in the Build tab of theoutput window

[0270] Debug and Simulation

[0271] Select Start debug from the Build menu. The Debug menu mayreplace the Build menu. A person can step through the code fromexecution point to execution point. Statements that are completed at theend of the current clock cycle are marked with an arrow.

[0272] The arrows are color coded as follows:

[0273] Yellow current point

[0274] White other points in this thread executed in this cycle

[0275] Grey points in other threads executed in this cycle

[0276] To set a breakpoint, click in the code editor on the line whereone wishes to set the breakpoint and then click the breakpoint button. Ared circle may appear at the beginning of that line. When the debuggerreaches that line, it may stop. FIG. 7 illustrates a breakpoint 700, inaccordance with one embodiment of the present invention.

[0277] Optimize Code as Necessary

[0278] One can examine the depth and speed of the code by compiling withthe -e option selected in the Compiler tab of the Project Settingsdialog. This creates:

[0279] an html file for the project, project.html

[0280] an html file for each file in the project files_c.html.

[0281] These files highlight the code according to the code area andtiming. The project.html file has links to all the html fileshighlighting the source code. It also links to the 5 top areas and 5 topdelays in the project. One can use this as a basis for optimizing thecode. An example of progressive optimization is given later.

[0282] Compile for Release

[0283] When one is satisfied with the project, select Build>Set ActiveConfiguration and choose the type of build required from the availableconfigurations. Release allows one to simulate the project without thedelays inherent in debug. It also allows one to compile Handel-Clibraries without debug information to protect intellectual property.Target is one of VHDL and EDIF. These are files that are ready to beplaced and routed. By default, most optimizations may be turned on.

[0284] Project Settings

[0285]FIG. 8 illustrates a project settings interface 800, in accordancewith one embodiment of the present invention. Project settings definehow projects are compiled and built. Select Project>Settings to see theProject settings dialog box. The different settings 802 are availablevia tabs 804. If one can't see the tab one want, then scroll the tabs byclicking on the arrows 806 at the end of the tabs. Note that some tabsare not available for an empty project. FIGS. 9A, 9B, and 9C illustrateavailable settings 900.

[0286] Independent Settings for Files

[0287] One can create independent settings for a file. A person mightwish to do this if one wanted to change the optimization level for aparticular file. Project settings for a file override the generalproject settings.

[0288] To create settings for a file, open the Project Settings dialog(either right-click the file in the File View and select Settings, orselect Project>Settings).

[0289] Select the name of the file that one wishes to affect in the filepane of the Project Settings dialog.

[0290] Make the appropriate changes.

[0291] Configurations

[0292] There are three types of configuration that one can select fromto build the application

[0293] Debug (default)

[0294] Release

[0295] Target (VHDL, EDIF etc.)

[0296] Debug is used to build a configuration that can be simulated anddebugged on the PC. In debug mode, one can view the contents ofregisters and step through the program's source code.

[0297] Release mode is used to create Handel-C intellectual property(libraries). It creates compiled code that has no debug messages and canbe used in another program. Release mode can also be used for high-speedsimulation.

[0298] In target mode, one gets a list of gates, ready to be placed androuted on an FPGA.

[0299] Defining Configurations

[0300]FIG. 10 illustrates a configurations graphical user interface1000, in accordance with one embodiment of the present invention. Onecan save a particular combination of settings as a project configurationusing the Build>Configurations menu item. This user-definedconfiguration can only be used in the project. Handel-C comes with fourdefault configurations: Build 1002, Debug 1004, VHDL 1006 and EDIF 1008.One can copy one of these configurations and then make changes to it.

[0301] Select Build>Configurations. . .

[0302] Click the Add button in the dialog that appears.

[0303] Enter a name for the new configuration, and select theconfiguration type that one wishes to use as a base in the Copy settingsfrom box.

[0304] More Complex Configurations

[0305] If one knows that he or she is going to have multiple projects(perhaps one needs to have two independent circuits on the same chip),it is better to create a workspace first and then add the projects toit.

[0306] If one has an existing workspace set up, it may be opened.Otherwise, select New from the File menu. Create a new workspace tostore the project(s). One may be asked for its name and location(pathname for the directory that it may be stored in). Either type thepathname in the Location box, or use the . . . button to browse for adirectory. Workspace files have .hw extensions.

[0307] Adding an Existing Project to a Workspace ps Select InsertProject into Workspace from the Project Menu.

[0308] Creating a Complex Project

[0309] If a project is a board or system, it may contain subprojects.When one creates a new complex project type (by writing a new .cf file)a dialog box appears when one clicks OK. The New Project Componentsdialog box asks what projects one wishes to use for the components ofthe project. One can either create a new project or select one withinthe workspace from the drop-down list. If the project exists but is notin the workspace, one can add it using the Insert Project button.

[0310] To ensure that the subprojects are built when one builds thecomplex project, he or she can set up the subprojects as dependent.Select Project>Dependencies . . .

[0311] One may be offered a list of the projects in the workspace. Checkthe ones that are desired to be rebuilt when building the complexproject.

[0312] Dependencies

[0313] Dependencies are used to ensure that files that are not part ofthe project are updated during a build. They also specify the order thatfiles may be compiled and built.

[0314] There are three types of dependencies used in Handel-C:

[0315] Project dependencies

[0316] File dependencies

[0317] External dependencies

[0318] The only one that can be changed directly is ProjectDependencies. The others show information calculated by the compiler.

[0319] Project Dependencies

[0320] The Project>Dependencies . . . dialog allows one to select otherprojects within the workspace that this project is dependent on.Projects listed here may be rebuilt as necessary when the project isrebuilt.

[0321] If one is building a complex project, such as a board or systemthat has several chips on it, he or she can create a separate projectfor each chip, and make the system project dependent upon them.

[0322] File ‘dependencies

[0323] File dependencies are listed in the file properties. They specifythe user include files that are not included in the project which areneeded to compile and build a selected file. They also specify whatother files within the project may be compiled before this file.

[0324] These dependencies are generated when one compiles a file. Onecan examine them by selecting a file in the File View pane of theworkspace window and typing Alt+Enter or right-clicking the file nameand selecting Properties from the shortcut menu.

[0325] External Dependencies

[0326] The External Dependencies folder appears in the workspace windowafter a project has been built. It contains a list of the header filesrequired by the project that are not included in the project.

User Interface

[0327] The Workspace Window

[0328] The workspace window contains workspaces and projects. Aworkspace is simply an area that one keeps projects in. It allows one toorganize the files that one need for each project. One could generallyuse one workspace per system (a system is the configuration that one aretargeting).

[0329] A project consists of everything one need to create one or morenet list files ready to be placed and routed on an FPGA, together withthe project settings. Project settings provide information about wherethe files for the project are stored, the target chip for the project,how the compilation may work, and optimization requirements. Projectscan be libraries (compiled Handel-C that is not targeted for aparticular output), cores (a piece of code, such as a function),complete net lists for a chip, boards (net lists for several chips in aspecified configuration) or systems (a combination of boards etc.). Inone embodiment, the core may optionally be compiled to a net list.

[0330] The workspace window has two views:

[0331] Fileview

[0332] Symbol view

[0333] File View

[0334]FIG. 11 illustrates a file view interface 1100, in accordance withone embodiment of the present invention. File view shows the workspace,its projects, and their source files and folders 1102. If there aremultiple projects in a single workspace, the current project name 1104may be in bold. The file view gives the structure of files in theproject. It has no relationship to the way one has stored files on ahard disk. It allows one to set up dependencies (what files are neededfor this project and what files or projects they depend upon) and managethe project by seeing which files are used within it.

[0335] One can adjust the space given to the Object and Info columns1106 by dragging the edge of the column heading. Double-clicking on asource file opens it in the code editor. Double clicking on anythingelse expands or contracts that branch of the workspace tree.Right-clicking on a filename or directory gives one a list ofcommonly-used commands.

[0336] File Properties

[0337]FIG. 12 illustrates a file properties 1200, in accordance with oneembodiment of the present invention. To operate, one may select a fileor directory in the workspace window 1202, then select View>Properties.This displays:

[0338] Inputs The tools used and the source file pathname(s) that toolrequires

[0339] Outputs The output files generated by the specified tool

[0340] Dependencies The header files (dependencies) this file requires.

[0341] Managing the Project Files

[0342] One can order the files within the project into folders. Thesefolders are only used to organize the files. They do not exist asfolders on the hard disk and have no effect on the directory structure.

[0343] Select Project>Add to Project>New Folder

[0344] Type the name of the folder in the dialog box that appears

[0345] Type the extension for the file types it should contain. One canleave the box blank.

[0346] Click OK

[0347] A new folder appears in the file view window.

[0348] Drag the files that are desired to be moved across to the folder.

[0349] Symbol View

[0350]FIG. 13 illustrates a workspace interface 1300 and the associatedicons, in accordance with one embodiment of the present invention. Asymbol is anything defined by the user (functions, variables, macros,typedefs, enums etc.). Symbol view allows one to see what one has in aproject. It is empty before one builds a project. When one builds theproject with the browse information enabled (set by default in the Debugconfiguration), a symbol table is created that allows one to examine thesymbols defined and used in the project. Selecting the Symbol View tab1302 of the workspace window then shows icons 1304 representing logicand architectural variables, functions and procedures.

[0351] Each icon is identified by its definition and use (references).External symbols (external variables and function names) appear inalphabetical order.

[0352] Double-clicking on a symbol expands it if it is expandable: ifnot, it opens the relevant source code file, with the appropriate linetagged Local symbols appear in alphabetical order within the function orprocedure where they are defined.

[0353]FIG. 14 illustrates a version test interface 1400, in accordancewith one embodiment of the present invention.

[0354] The Source Browser

[0355]FIG. 15 illustrate a browse and associated results interface 1500,in accordance with one embodiment of the present invention. One canbrowse for definitions and references 1502 without using symbol view.When one selects the Source Browser command from the Tool menu, one isgiven a Browse dialog box.

[0356] Enter the symbol being searched for, and a dialog box may beshown giving its definition and references to it.

[0357] Browse Commands

[0358] If one selects a symbol name in a source file, one can use thebrowse commands and buttons to find its definitions and references inall the files used in a project. FIGS. 16A and 16B illustrate browsingcommands 1600, in accordance with one embodiment of the presentinvention.

[0359] Editing

[0360] The Code Editor

[0361] The code editor is a simple editor that resides in its ownwindow. The syntax is color coded. One can change the color codes byselecting the Format tab from the Tools>Options dialog box. The defaultvalues are:

[0362] Comments green

[0363] Handel-C keywords blue

[0364] Number black

[0365] String black

[0366] Operator black

[0367] One can use standard editing commands within the code window.These are accessible from the Edit menu. FIG. 17 is a table of editingcommands 1700, in accordance with one embodiment of the presentinvention. The Edit menu also has the Bookmarks and Browse sub-menus andthe Breakpoints command.

[0368] Find Commands

[0369] Handel-C has simple Find and Replace commands that allow one tosearch for text in the current file, and the Find in Files command,which allows one to search for a string in all the files in a directory.The output from this command can be sent to two different window panes,allowing one to view the results of two searches. To choose which paneis selected check or uncheck the Output to pane 2 box in the Find inFiles dialog.

[0370] These searches work line by line, which means that one cannotmatch text that spans more than one line. One can also search usingregular expressions. To do this, check Regular expression in the Findand Find in Files dialog box. The regular expressions supported arelisted below. FIG. 18 is a table of regular expressions 1800, inaccordance with one embodiment of the present invention.

[0371] Bookmarks Submenu

[0372] The Bookmarks submenu allows one to set and clear bookmarkswithin the files. Once one has set bookmarks in the file, one can movethrough the bookmarks by selecting Next Bookmark (F2) or PreviousBookmark (Shift F2).

[0373] To Set a Bookmark

[0374] Select the line where one wishes to place the bookmark

[0375] Press the toggle bookmark button

[0376] OR

[0377] Right-click the line and select Toggle bookmark from the shortcutmenu that appears

[0378] OR

[0379] Select Edit>Bookmarks>Toggle Bookmark (Ctrl F2).

[0380] To Move to a Bookmark

[0381] Select Edit>Bookmarks>Next Bookmark (F2) or press the nextbookmark button to move forward through the bookmarks

[0382] Select Edit>Bookmarks>Previous Bookmark (Shift F2) or press theprevious bookmark button to move backwards.

[0383] To Remove a Bookmark

[0384] Select the line where one wishes to clear the bookmark Press thetoggle bookmark button

[0385] OR

[0386] Right-click the line and select Toggle bookmark from the shortcutmenu that appears

[0387] OR

[0388] Select Edit>Bookmarks>Toggle Bookmark (Control F2).

[0389] To Remove All Bookmarks

[0390] Select Edit>Bookmarks>Clear All Bookmarks (Control Shift F2) orpress the clear all bookmarks button to clear all bookmarks

[0391] Breakpoints Command

[0392] The Breakpoints command allows one to set, enable and disablebreakpoints.

[0393] Breakpoints are fully discussed hereinafter in greater detail.

[0394] Breakpoints Alt+F9 Display a dialogue box for editing thebreakpoints list for this project

[0395] Browse Submenu

[0396] The Browse submenu allows one to find definitions of andreferences to selected variables or other symbols. If one makes a changeto a variable, this is a quick way of finding everywhere that thevariable is used.

[0397] To Find the Definition of a Variable or Other Symbol

[0398] Select the symbol name in an edit window.

[0399] Select Edit>Browse>Go to Definition or click the button

[0400] To Find the First Reference to a Variable or Other Symbol

[0401] Select the symbol name in an edit window.

[0402] Select Edit>Browse>Go to Reference or click the button

[0403] To Move Through the References to and Definitions of a Variableor Other Symbol

[0404] Select the symbol name in an edit window.

[0405] To move forward, select Edit>Browse>Next Definition Reference orclick the button

[0406] To move backward, select Edit>Browse>Previous DefinitionReference or click the button

[0407] To Return to the Position Before Starting Browsing

[0408] Select Edit>Browse>Pop Context or click the button

[0409] Saving Changes

[0410] If one has not saved changes to a file, an asterisk appears afterthe filename on the title bar. One may be asked if he or she wishes tosave changes when a file is closed.

[0411] Files and Paths

[0412] The current directory is the directory containing the currentproject's .hp file. All relative pathnames are calculated from thatcurrent directory.

[0413] Project Files Generated

[0414] When one creates a workspace, a directory is created for thatworkspace. Projects within the workspace may be in the same directory ora sub-directory. When one builds a project, a directory is created forthe build results. The default directory name is the name of the buildtype (Debug, Release, VHDL or EDIF). One can change this by setting theOutput Directory values in the General tab of the Project Settingsdialog.

[0415] These are the files built for a workspace prog.hw, containing aproject example 1, consisting of one Handel-C file, prog.c that has beencompiled for simulation. The files may all be stored in the Debugfolder. FIG. 19 is a table of various project files 1900, in accordancewith one embodiment of the present invention.

[0416] Search Paths

[0417] Code files that one has added to the project workspace may becompiled and built. Header files may only be found by the pre-processorif they exist on a known path.

[0418] The directories searched are in the following order:

[0419] 1. Directory containing the Handel-C file that has the #includedirective (if within quotes).

[0420] 2. Directories listed in Project>Settings>Preprocessor>Additionalinclude directories (in the order specified)

[0421] 3. Directories listed in the Directories pane of theTools>Options dialog (in the order specified)

[0422] 4. Directories in the HANDELC_CPPFLAGS environment variable (inthe order specified)

[0423] Windows and Toolbars

[0424] The Handel-C user interface has standard scrollable windows andcustomizable toolbars. One can customize:

[0425] The way the edit and build environment is laid out (position ofworkspace and output windows etc.)

[0426] The way document windows are laid out (this is specific to eachworkspace)

[0427] The debugger layout (the way windows look when you're in thedebugger)

[0428] These layouts are stored. The edit and build and the debuglayouts are kept for the copy of Handel-C. If one changes them, he orshe changes them for every project. The document window layout is keptwith the workspace, and can change whenever he or she changes thecurrent workspace.

[0429] Window Types

[0430] Document windows are movable within the Handel-C window. One canresize them and drag them about. Docking windows can either be docked atone of the window margins, or can float above the other windows. When awindow is docked it has no title-bar. If one has docked a code editorwindow, the file name appears in brackets after the project title in theHandel-C title bar. To float a docked window, double-click its border.To dock a floating window, either double-click its border, or drag itstitle bar to a docking position.

[0431] Splitting Windows

[0432] One can split text windows by dragging the small box immediatelyabove the vertical scroll bar.

[0433] The Windows Menu

[0434] The windows menu allows one to control the size and display ofediting windows. It has the following commands:

[0435] New window Create a copy of the current window

[0436] Split Split the window into two or four views.

[0437] Docking view Enable/disable docking view of selected dockablewindow

[0438] Close Close current window

[0439] Close All Close all windows

[0440] Next Move to next pane of a split window

[0441] Previous Move to previous pane of a split window

[0442] Cascade Cascade all open windows with title bars visible

[0443] Tile Horizontally Display all windows, splitting the viewing areahorizontally

[0444] Tile Vertically Display all windows, splitting the viewing areavertically

[0445] Arrange Icons Arrange minimized window icons along bottom ofviewing area

[0446] Windows . . . Open Windows dialog

[0447] Windows Dialog

[0448] The Windows dialog gives the names of all open edit windows. Aperson can make one of them the current window, or select a group ofwindows to be saved, closed or tiled.

[0449] Full Screen Display

[0450] The Full Screen command on the Edit menu displays the code editorpane at maximum size. The normal menu bars and toolbars are not visible.To return to a normal view, click the no fill screen button.

[0451] Toolbars

[0452] When one starts Handel-C, toolbars appear under the menu bar.They are:

[0453] The standard toolbar

[0454] Build mini-bar

[0455] Browse mini-bar

[0456] Debug mini-bar

[0457] Bookmark mini-bar.

[0458] Standard Toolbar Buttons

[0459] The standard toolbar buttons are a frequently used subset fromthe File, Edit and View menus.

[0460] Changing Toolbars

[0461] The toolbars in Handel-C are dockable. They can be docked at oneof the edges of the Handel-C window, or they can float. One can change atoolbar from docked to floating and back by double clicking on it. Onecan move them by dragging the title bar or the double bar.

[0462] The Status Bar

[0463] The status bar is visible at the bottom of the Handel-C window.It displays information about items when the mouse is over them.

[0464] The Tools Menu

[0465] The tools menu has the Source Browser command and commands tocustomize the copy of Handel-C.

[0466] The Source Browser Command

[0467] The Source Browser command allows one to search for names ofvariables and functions within the code. It directs one to theirdefinition and lists references to them. Its use is more fully discussedhereinafter in greater detail.

[0468] Customizing the Interface

[0469]FIG. 20 illustrates a GUI 2000 for customizing the interface, inaccordance with one embodiment of the present invention. The Customize .. . command brings up the Customize dialog. The Toolbar tab 2002 allowsone to change the display of toolbars utilizing various options 2004, asshown. To use, one may check a toolbar in the toolbar pane to displayit, uncheck it to hide it.

[0470] Show Tooltips Check this to popup the purpose of a button whenthe mouse cursor is over it.

[0471] Cool Look Check this to make the buttons appear two-dimensional

[0472] Large Buttons Check this to increase the button size

[0473] Large Icons Check this to have large icons on large buttons.

[0474] The Command tab allows one to add menus and buttons to thetoolbar and menu bar. The right-hand pane displays the buttons and Menucommands available.

[0475] Select the button or menu that one wishes to add and drag it tothe toolbar or menu bar. If one drags a menu command to a toolbar, itappears as a button. If one drags it to an empty area, it appears as anew floating window.

[0476] Removing Buttons and Menus

[0477] One can remove buttons from a toolbar by opening theTools>Customize dialog and then dragging them off the toolbar. One canremove menus from the menu bar by opening the Tools>Customize dialog anddragging the menu name off the toolbar.

[0478] To restore a toolbar to its previous state, select the Toolbarstab of the Tools>Customize dialog. Select the toolbar (under theToolbars tab) or the menu (under the Commands tab)

[0479] Options

[0480] The Tools>Options command allows one to set options:

[0481] Editor Set the window options for the editor. Define when filesare saved.

[0482] Tabs Define how tabs are handled and whether Auto-Indent is used.

[0483] Debug Set the default base used to display numbers in the debugwindows. This information is over-ruled by the Handel-C showspecification.

[0484] Format Define the color and font of text and markers in windows.

[0485] Workspace Set the number of recently opened workspaces in theworkspace list.

[0486] Directories Set the directories that may be searched for includeand library files used in projects.

[0487] Editor

[0488] Vertical scroll bar Check to display vertical scroll-bar

[0489] Horizontal scroll bar Check to display horizontal scrollbar

[0490] Automatic window recycling Display files opened by the IDE(integrated development environment) in an existing window

[0491] Selection margin Use a selection margin in the editor window toenable one to select paragraphs, etc.

[0492] Drag and drop text editing Edit by selecting an area, anddragging it to a new position

[0493] Save before running tools Save files before running tools definedin the Tools menu

[0494] Prompt before saving files Ask before saving

[0495] Automatic reload of externally modified files If a file is openin Handel-C, and then modified by something outside Handel-C, loadchanges from disk automatically.

[0496] Tabs

[0497] File type Define settings for specified file types or definedefault settings.

[0498] Tab size Equivalent number of spaces per tab

[0499] Insert spaces/Keep tabs Select whether to use spaces or tabs infile

[0500] Auto indent Check to auto-indent text to above line's indent

[0501] Debug

[0502] Base for numbers Select default display base in debug windows

[0503] Format

[0504] Category Select window type(s) to modify

[0505] Font Select font to display text in

[0506] Size Select display font size

[0507] Colors Select text type to modify

[0508] Foreground: Set foreground color

[0509] Background: Set background color.

[0510] Sample Display sample text in selected settings

[0511] Reset All Return to default settings

[0512] Workspace

[0513] Default workspace list Set number of recent workspaces in theFile>Recent Workspaces command

[0514] Directories

[0515] Show directories for: Select include path list or Library pathlist

[0516] Add or remove directory paths to search for include files orlibrary files.

Compiler

[0517]FIG. 20A illustrates a method 2050 for a compiler capable ofcompiling a computer program for programming a hardware device. Ingeneral, in operation 2052, a first net list is created with a firstformat based on a computer program. Further, in operation 2054, a secondnet list is created with a second format based on the computer program.In an aspect of the present invention, the first format may includeEDIF. As another aspect, the second format may include VDHL, XNF, etc.It should be noted, however, that any other formats may be employed perthe desires of the user.

[0518] It is important to note that the first net list and the secondnet list are created utilizing a single compiler. Note operation 2056.As an option, the computer program from which the first net list wascreated may be the same as the computer program from which the secondnet list was created. More information regarding the compiler will nowbe set forth.

[0519] The Handel-C compiler compiles and optimizes Handel-C source codeinto a file suitable for simulation or a net list file which can beplaced and routed on a real FPGA. The compiler is normally invokedautomatically when the user selects an option from the Build menu.

[0520] Once the compile has completed, an estimate of the number of NANDgates estimate required to implement the design is displayed in theoutput window. The compiler uses the GNU preprocessor. Flags can bepassed to the preprocessor using the Preprocessor tab of theProject>Settings dialog box. If one wishes to run the compiler from acommand line, one may do so by using the command handelc. A completelist of the command line options is set forth hereinafter.

[0521] The Build Process

[0522]FIG. 21 illustrates a build interface 2100, in accordance with oneembodiment of the present invention. A build happens when:

[0523] one click on the build button 2102. p1 one has uncompiled filesand one select one of the Start Debug commands in the Build menu.

[0524] one selects Build or Rebuild All from the Build menu

[0525] This should:

[0526] preprocess header files and compile dependent header files

[0527] compile any files that have been added, changed and saved sincethe last compilation and also compile any files dependent upon them.

[0528] compile all dependent projects.

[0529] link the compiled files together

[0530] calculate the number of gates used

[0531] build a symbol table

[0532] generate a simulatable file or a net list.

[0533] If one changes the configuration for a project, he or she mayneed to compile all the files. Select the Build>Rebuild All command toensure that all the files are recompiled.

[0534] The results of the compilation and build are displayed in theBuild window. Double-clicking an error takes one to the appropriate linein the source file.

[0535] Checking Code Depth and Speed

[0536] One can examine the depth and speed of the code by compilingusing the -e option. This creates:

[0537] an html file for the project,project.html

[0538] an html file for each file in the project files_c.html. Thesehighlight areas of code according to how much area or delay may berequired to implement it.

[0539] One can look at these files by opening them in any Internetbrowser. project.html.

[0540] The project.html file has links to all the files_c.html filesthat highlight the source code. It also links to the 5 top areas and 5top delays in the project.

[0541] file_c.html

[0542] The html versions of the source files show two versions of thesource code. The first is colored according to the area required toimplement the code; the second according to the amount of delay. Coolcolors (blues and greens) indicate a small area or delay; hot colors(red and yellow) show where there are large areas or delays. There arefull color tables at the end of each section. The five largest delaysand areas are underlined and tagged with the number of gates or logiclevels needed. These estimates are only a guide since full place androute is needed to get exact logic area and timing information.

[0543] The Build Menu

[0544]FIG. 22 illustrates table showing a build menu 2200, in accordancewith one embodiment of the present invention.

Debugger and Simulator

[0545]FIG. 22A illustrates a method 2250 for debugging a computerprogram, in accordance with one embodiment of the present invention. Ingeneral, in operation 2252, a plurality of threads is identified in acomputer program.

[0546] Selection of one of the threads is allowed in operation 2254. Inanother aspect, the thread may be selected by inserting a breakpoint inthe computer program. As may soon become apparent, this or any otherdesired method may be used to carry out the selection. As such, the usercan choose to jump between threads existing in the same clock cycle.Note use of the “follow” command hereinafter.

[0547] The selected thread is then debugged. See operation 2256. In oneaspect of the present invention, a default thread may be initiallydebugged without user action (automatically). As an option, the defaultthread may be a thread that is first encountered in the computerprogram. In a further aspect, the debugging may utilize a clockassociated with the selected thread.

[0548] The simulator thus allows one to test the program without usingreal hardware. It allows one to see the state of every variable(register) in the program at every clock cycle. One can select whichvariables are to be displayed by using the Watch and Variable windows.One can see the current threads running in the Threads window and thecurrent clocks used in the Clocks window. A person can see the currentfunction, and what functions were called to reach it, in the Call Stackwindow.

[0549] One can run the code in the simulator in several ways:

[0550] Run until the end (never ends on a continuous program loop)

[0551] Run until one reaches the current cursor position

[0552] Run until one reaches a user-defined breakpoint

[0553] Step through the code.

[0554] When one is using the debugger one can be running the simulation(run mode) or pausing the simulation (break mode). When the simulationhas paused (in one of the ways given above or by using the Breakcommand) one can easily examine variables, change window displays, orset breakpoints. When the simulation is in run mode, one can onlyobserve.

[0555] When one starts the debugger, a Debug menu appears. FIGS. 23A and23B illustrate the various commands 2200 associated with the debug menu,in accordance with one embodiment of the present invention.

[0556] One can also set breakpoints on valid code lines. When thedebugger reaches a breakpoint it may pause until one requests it tocontinue.

[0557] The Debugger Interface

[0558] The debugger interface consists of a plurality of windows. FIG.24 illustrates a table 2400 showing the various windows associated withthe debugger interface, in accordance with one embodiment of the presentinvention.

[0559] Symbols in the Editor Window

[0560] The statements associated with the current clock tick are markedwith arrows. All of these statements execute together. If there is a parstatement in the code, the execution may split into separate threads,one for each branch of the par statement. The threads execute inparallel. When one is debugging, one can only follow one thread at atime. The current thread has arrows marked in yellow and white. Whitearrows show combinatorial code that may be executed on the next clocktick. A yellow arrow shows the current point.

[0561] The other threads have the points that may be executed on thecurrent clock cycle in dark gray. If one single-steps through theHandel-C code, one may see the arrows move.

[0562] The Variables Window

[0563]FIG. 25 illustrates a variables window interface 2500, inaccordance with one embodiment of the present invention. The Variableswindow always shows the current variables 2502. When their valueschange, the color changes from black to red. The window has two tabs2504, Auto and Locals. The Auto tab shows variables that have beenautomatically selected. They are variables used in the current andprevious statement in the current thread. It also displays return valueswhen one comes out of or step overs a function.

[0564] The Locals tab shows the variables that are local to the currentfunction or macro.

[0565] The Watch Windows

[0566] There are four watch windows. One can select variables to bedisplayed in each window, and look at their values at any breakpoint oras one step through the program.

[0567] One can add a variable to the watch window by typing its name.The watch window has an expression evaluator. If one types in anexpression, the result may be evaluated.

[0568] The Call Stack Window

[0569]FIG. 26 illustrates the current positioning function blib 2600,and the related call stack window. The functions called on the way tothe current function are displayed in the Call Stack window. This showsthe current function at the top of the window, and the functions thathave not yet completed beneath.

[0570] The current function in the current thread is marked with ayellow arrow. If multiple threads that are running different functions,the other current functions are marked with green arrows.

[0571] The Threads Window

[0572]FIG. 27 illustrates a threads window interface 2700, in accordancewith one embodiment of the present invention. All threads 2702 aredisplayed in the Threads window.

[0573] The thread column shows the thread ID 2704 (how the simulatoridentifies the thread) The yellow arrow 2706 indicates the currentthread. The grey arrows 2708 indicate threads with the same clock as thecurrent thread. The Detail column gives an outline of the provenance ofthis thread. The picture shows four threads that are branches of thereplicated par in queue.c. They are distinguished here by the par(i=XXX) detail. The Location column tells one the current line number ofthat thread in the code.

[0574] Right-click in the Threads window to see a menu:

[0575] Show Location shows one the source file and scrolls to the rightposition

[0576] Follow tells the debugger to follow that thread (make it thecurrent thread)

[0577] The Clocks Window

[0578]FIG. 28 illustrates a variables window interface 2800, inaccordance with one embodiment of the present invention. All clocks 2802used are displayed in the Clocks window. The current clock is markedwith a yellow arrow. It is identified by the full pathname of the filereferencing it. The clock cycle count 2804 is also displayed in theClocks window. Double-clicking a clock takes one to the clockdefinition.

[0579] Using the Debugger Commands

[0580] One can use the debugger commands to go through every line of thecode, step over functions and macros, or the run the code until abreakpoint has been reached.

[0581] Single Stepping

[0582] The simulator steps through the program, one clock cycle at atime. Essentially, assignments, and reads and writes to channels takeone clock cycle, everything else is ‘free’. In a sequential language,such as ISO-C, one can step through code one line at a time, and onestop at an execution point. Because Handel-C is a parallel language,there can be multiple execution points. Because parallel threads areimplemented as separate pieces of logic, multiple statements may executeon the same clock tick.

[0583] Single stepping through the program does not mean steppingthrough it one line at a time, or one statement at a time.

[0584] One can choose to Step Into, Step Out of or Step Over functionsand macros. If one wants to move forward a single line, rather than acomplete clock cycle, one can use the Advance command.

[0585] Using Breakpoints

[0586]FIG. 29 illustrates a breakpoints window interface 2900, inaccordance with one embodiment of the present invention. If a persondoes not wish to single-step through the code, one can run until he orshe reaches a breakpoint.

[0587] Setting Breakpoints

[0588] Select the line of code where one wishes the simulator to pause.(Use Edit>Find to hunt for known names.)

[0589] Click the breakpoint button

[0590] OR

[0591] Select Break from the Debug menu.

[0592] OR

[0593] Right-click the mouse and select Insert Breakpoint

[0594] Disabling Breakpoints

[0595] Breakpoints can be active or inactive. If one wishes to keep abreakpoint but not to stop at it,

[0596] Find the line of code where the breakpoint is set; right-clickthe mouse and select Disable Breakpoint

[0597] All breakpoints are listed in the Edit>Breakpoints dialog box.One can also disable a breakpoint by unchecking its box in this dialog.

[0598] Removing Breakpoints

[0599] Find the line of code where the breakpoint is set.

[0600] Click the breakpoint button

[0601] OR

[0602] Right-click the mouse and select Remove Breakpoint

[0603] OR

[0604] Open the breakpoints dialog (Edit>Breakpoints), select the

[0605] breakpoint(s) to be removed and click Remove.

[0606] Breakpoints in Replicated Code

[0607] If one sets a breakpoint in replicated code, a breakpoint may beset in every copy of the code. When one steps through it, the arrows maynot appear to advance, but one can see the thread changing in theThreads window.

[0608] Breakpoints in Macros and Inline Functions

[0609] One cannot set breakpoints in macro expressions. If a person setsa breakpoint in an inline function or a macro procedure, the breakpointmay occur every time that the code is used.

[0610] Following Threads

[0611] The default thread followed is the one that appears first in thecode. One can follow another thread by:

[0612] Selecting the code to follow in the code editor, right-clickingthe mouse and selecting Follow Thread

[0613] OR

[0614] Opening the Threads window, selecting a thread, right-clickingand selecting Follow Thread

[0615] OR

[0616] By setting a breakpoint within that thread.

[0617] Setting a breakpoint in a thread makes that the current threadwhen the breakpoint is reached.

[0618] Selecting Clocks

[0619] The clock used is the one associated with the current thread. Onecan change the clock domain followed by:

[0620] following a different thread

[0621] setting a breakpoint within the thread to be followed

[0622] All clocks used are displayed in the Clocks window. The currentclock is marked with a yellow arrow. It is identified by the fullpathname of the file referencing it.

[0623] The current clock cycle count is also displayed in the Clockswindow.

[0624] Following Function Calls

[0625] The way a function has been called is displayed in the Call Stackwindow. This shows the current function at the top of the window, andthe uncompleted functions that called it beneath. The current functionin the current thread is marked with a yellow arrow. If multiple threadsare running different functions, the other current functions are markedwith green arrows. If a function has stopped at a breakpoint, thebreakpoint marker is shown in the Call Stack window.

[0626] Examining Variables

[0627] There are two windows for examining variable values

[0628] Watch

[0629] Variables

[0630] By default variables are displayed in decimal. One can change thebase by right-clicking within the window and selecting a new value fromthe pop-up menu. One can change the display base of an individualvariable using the Handel-C specification with {base=n}. One can turnoff the display of a variable by using the Handel-C specification with{show=0}.

[0631] int 32 pike with {show=0};

[0632] Arrays and structures are displayed with a+button next to thename. Click on this button to display individual array elements orstructure members.

[0633] Configuration

[0634] In debug mode, the project configuration for debug is set bydefault.

[0635] Debug Configuration

[0636] The settings specific to debug are:

[0637] Preprocessor defines the variables DEBUG and SIMULATE. Thisallows one to set up the code (see examples below) according to whethera person is using the simulator, e.g. use simulator channels instead ofreal interfaces.

[0638] Compiler Generate Debug and Generate warning boxes checked

[0639] Linker Output format set to Simulator; Save browse info boxchecked; Generate estimation information option (create html files)switched off.

[0640] Debugger Working directory for debugger set to current (.).

[0641] Optimizations High-level optimization switched on.

Hardware Embodiments

[0642] If one is approaching Handel-C from a hardware background, oneshould be aware of these points:

[0643] Handel-C is halfway between RTL and a behavioral HDL. It is ahigh-level language that requires one to think in algorithms rather thancircuits.

[0644] Handel-C uses a zero-delay model and a synchronous design style.

[0645] Handel-C is implicitly sequential. Parallel processes may bespecified.

[0646] All code in Handel-C (apart from the simulator chanin and chanoutcommands) can be synthesized, so one may ensure that he or she disablesdebug code when he or she compiles to target real hardware.

[0647] Signals in Handel-C are different from signals in VHDL; they areassigned to immediately, and only hold their value for one clock cycle.

[0648] Handel-C has abstract high-level concepts such as pointers.

[0649] Points of Difference

[0650] If one is an experienced C user, he or she may be caught unawaresby some of the differences between C and Handel-C. The differences aresummarized hereinafter.

[0651]FIGS. 30 and 31 illustrate a table showing various differences3100 between Handel-C and the conventional C programming language, inaccordance with one embodiment of the present invention.

Porting C to Handel-C

[0652] Introduction

[0653] This section illustrates the general process of porting anexisting conventional C routine to Handel-C. The general issues arediscussed first and then illustrated with the particular example of anedge detection routine. This example illustrates the whole conversionprocess from conventional C program to optimized Handel-C program andalso shows how to map conventional C onto real hardware. There is also asection detailing the differences between conventional C and Handel-C.

[0654] General Porting Issues

[0655] In general, there are a number of stages to porting and mapping aconventional C program to hardware. These are:

[0656] 1. Decide on how the software system maps onto the targethardware platform. For example, external RAM connected to the FPGA canbe used to hold buffers used in the conventional C program. This mappingmay also include partitioning the algorithm between multiple FPGAs and,hence, splitting the conventional C into multiple Handel-C programs.

[0657] 2. Convert the conventional C program to Handel-C and use thesimulator to check correctness. Remember that there may be optimizationsthat can be made to the algorithm given that a Handel-C program can useparallelism. For example, one can sort numbers more quickly in parallelby using a sorting network. This form of coarse grain parallelism canprovide massive performance gains so time should be spent on this step.

[0658] 3. Modify code to take advantage of extra operators available inHandel-C. For example, concatenation and bit selection can be used whereconventional C programs may use shifts and masks. Simulate again toensure program is still correct.

[0659] 4. Add fine grain parallelism such as making parallel assignmentsor executing individual instructions in parallel to fine-tuneperformance. Again, simulate to ensure that the program still functionscorrectly.

[0660] 5. Add the hardware interfaces necessary for the targetarchitecture and map the simulator channel communications onto theseinterfaces. If possible, simulate to ensure mapping has been performedcorrectly.

[0661] 6. Use the FPGA place and route tools to generate the FPGAimage(s).

[0662] These steps are obviously guidelines only—some of the stages maynot be relevant to the design or one may require extra stages if thedesign does not fit this example flow. This list provides a startingpoint and guidelines for how to approach the process of porting thecode. A full example follows after the section comparing C and Handel-C.

[0663] One of the most important factors in selecting a goodpartitioning of a program between hardware and software is to take intoaccount the cost of communicating data between the two halves of thepartition. The communication link between the hardware and software isdetermined by a number of parameters particular to a given target. Theseparameters include bandwidth, latency, and (per-message) overhead.

[0664] For some languages, it is possible to determine exactly theamount of data that would be transferred by an operation such as afunction call, since all the data is passed in one direction by thearguments, and in the other direction by the return value. However, manyother languages (including C) pass data implicitly using pointers. Forthese languages static analysis techniques cannot yield usefullyaccurate results. It is in this situation that the techniques presentedare applicable.

[0665] One technique relies on dynamic analysis of the source program.The source program is compiled to platform independent bytecode. Asuitable bytecode interpreter is augmented such that accesses to memory(typically load and store instructions) can be traced. In this way thememory use behavior of each part of the source program can be examinedby executing the program and analyzing the generated trace. A simplisticimplementation of this technique suffers from the problem of generatinga very large amount of profiling data. The present embodiment uses twoalternative techniques to solve this problem:

[0666] 1. During execution of a single function (or set of functionsgrouped as a domain) the present embodiment records a map of all thememory accessed. At the end of execution of the function outputs only acompressed version of this map (compressed using a technique such asrun-length encoding) Since functions may typically tend to use blocks ofmemory in ranges, rather than a fully random access pattern, thisresults in significant savings in the size of the generated output. Theoutput is then analyzed post-hoc to determine where memory transferswould have taken place between domains of a partitioned system.

[0667] 2. Alternatively, some of the analysis can happen on-line duringthe execution of the program. In this case, a memory map of the programis kept which records which functions (or groups of functions) havevalid copies of small ranges of memory (micropages). When a functionreads for an area of memory, this map is checked to see which functionshave a valid copy of the data. If the current function has a valid copyno further action is taken. If no function has a valid copy of the datathen it is taken as coming from an external source function. Otherwise atransfer from one of the other functions to the current function isrecorded, and the map records that the current function now has a validcopy of the micropage. When a write occurs, exactly the same actiontakes place except the ownership of the micropage becomes only thecurrent function, no other functions now possess valid (up-to-date)copies of the data in the given page. The result of the execution of aprogram in this way is a 2-dimensional table recording data transfersfrom functions to functions. This data can then be further analyzed togive estimates for the performance of given partitions, be used todecide partitions, or be presented in a graphical form (such as adirected graph). It has been assumed in the above that the compiled codeis executed within a virtual machine. It is possible via modification tothe compiler to generate native code with appropriate traps on memoryaccesses and calls to functions implemented either of the abovestrategies. This results in an improvement in performance over thebytecode alternative.

[0668] Comparison Between Conventional C and Handel-C

[0669] This section details the types, operators, and statementsavailable in conventional C and Handel-C. The tables should be used toget an idea of which parts of the conventional C program need to bealtered. Differences in implementation between Handel-C and ISO-C:

[0670] Functions may not be recursive.

[0671] Old-style function declarations are not necessarily supported.

[0672] Variable length parameter lists are not necessarily supported.

[0673] One may not necessarily change the width of a variable by casting

[0674] One cannot convert pointer types except to and from void, betweensigned and unsigned and between similar structs

[0675] Floating point is not necessarily supported, but may be supported(optionally) in some embodiments

[0676] Statements in Handel-C may not cause side-effects. This has thefollowing consequences:

[0677] local initializations are not supported.

[0678] the initialization and iteration phases of for loops may bestatements, not expressions.

[0679] shortcut assignments (e.g. +=) may appear as standalonestatements.

[0680] Types, Type Operators and Objects

[0681]FIG. 32 illustrates a table of types, type operators and objects3200, in accordance with one embodiment of the present invention

[0682] Statements

[0683]FIG. 33 illustrates a table of statements 3300, in accordance withone embodiment of the present invention.

[0684] Expressions

[0685]FIG. 34 illustrates a table of expressions 3400, in accordancewith one embodiment of the present invention.

[0686] In Both/In Conventional C Only/In Handel-C Only

[0687] The Edge Detector Example (C to Handel-C)

[0688] The edge detector consists of a number of versions of the sameapplication that detail the process of porting a conventional Capplication to a Handel-C application. All but the final stage(targeting real hardware) are presented as complete examples that may besimulated with the Handel-C simulator. They are stored as separateprojects within a single workspace.

[0689] The original C code is supplied in source and compiled versions.One can execute this code, and simulate the different versions of theported code. Note that the examples use specific hard-coded filenamesfor the image data. The image data filenames may be exactly the same asthose given in the examples, or the source code may be edited andrecompiled.

[0690] The Original Program

[0691] The example used in this section to illustrate the portingprocess is that of a simple edge detector. Each of the stages outlinedin the previous section is illustrated with complete code listings. Theoriginal conventional C program is given below.

[0692] #include <stdio.h>

[0693] #include <stdlib.h>

[0694] /*

[0695] * Define name of input/output files

[0696] */

[0697] #define SourceFileName “../Data/source.raw”

[0698] #define DestFileName “../Data/dest.raw”

[0699] /*

[0700] * Define parameters of image and threshold for edges

[0701] */

[0702] #define WIDTH 256

[0703] #define HEIGHT 256

[0704] #define THRESHOLD 16

[0705] /*

[0706] * Edge detector procedure

[0707] */

[0708] void edge_detect(unsigned char *Source, unsigned char *Dest)

[0709] {

[0710] int x, y; Targeting Hardware

[0711] /*

[0712] * Loop round for every pixel

[0713] */

[0714] for (y=1; y<HEIGHT; y++)

[0715] for (x=1; x<WIDTH; x++)

[0716] {

[0717] /*

[0718] * Determine whether there is an edge here

[0719] */

[0720] if (abs(Source[x+y*WIDTH] -

[0721] Source[x-1+y*WIDTH])>THRESHOLD ||

[0722] abs(Source[x+y*WIDTH]-

[0723] Source[x+(y−1)*WIDTH])>THRESHOLD)

[0724] Dest[x+y*WIDTH]=0xFP;

[0725] else

[0726] Dest[x+y*WIDTH]=0;

[0727] }

[0728] }

[0729] /*

[0730] * Main program

[0731] */

[0732] int main(void)

[0733] {

[0734] unsigned char *Source=malloc(WIDTH*HEIGHT);

[0735] unsigned char *Dest=malloc(WIDTH*HEIGHT);

[0736] FILE *FilePtr;

[0737] /*

[0738] * Read image from file

[0739] */

[0740] FilePtr=fopen(SourceFileName, “rb”);

[0741] fread(Source, sizeot(unsigned char), WIDTH*HEIGHT, FilePtr);

[0742] fclose(FilePtr);

[0743] /*

[0744] * Do edge detection

[0745] */

[0746] edge_detect(Source, Dest);

[0747] /*

[0748] * Write results back to file

[0749] */

[0750] FilePtr=fopen(DestFileName, “wb”);

[0751] twrite(Dest, sizeof(unsigned char), WIDTH*HEIGHT, FilePtr);

[0752] fclose(FilePtr);

[0753] return 0;

[0754] }

[0755] The file reads data from a raw data file into a buffer. Thefunction edge_detect then performs a simple edge detection and storesthe results in a second buffer which is stored in a second file. Theedge detection is performed by subtracting the pixel values for adjacenthorizontal and vertical pixels, taking the absolute values andthresholding the result. The source and destination images are both 8bit per pixel greyscale images. The conventional C source file and acompiled version are provided along with an example image (source.bmp).One can run the program now to see the results. This is done using thefollowing commands:

[0756] 1. Convert the example BMP file to raw data with the bmp2rawutility. bmp2raw -b source.bmp source.raw 8bppdest.rgb

[0757] 2. Execute the conventional C edge detector.

[0758] edge_c

[0759] 3. Convert the output from the edge detector back to a BMP fileusing the raw2bmp utility:

[0760] raw2bmp -b 256 dest.raw dest_c.bmp Sbppsrc.rgb

[0761] One can use the standard Windows 98 and NT Paint utility todisplay the source and destination BMP files to compare results.

[0762] First Attempt Handel-C Program

[0763] The first step is to port the conventional C to Handel-C with asfew changes as possible to ensure that the resulting program workscorrectly. The file handling sections of the original program aremodified to read data from a file and write data back to a file usingthe Handel-C simulator. The resulting program is given below.

[0764] The following points should be noted about the port:

[0765] 1. The Source and Dest buffers have been replaced with two RAMs.

[0766] 2. An abs( ) macro expression provided in stdlib.h has been usedto replace the standard C function.

[0767] 3. The x and y variables have been given widths equal to thenumber of address lines required for the RAMs to simplify the index ofthe RAM. Without this, each variable would have to be padded with zerosin its MSBs to avoid a width conflict when accessing the RAM.

[0768] 4. Temporary variables have been used for the three pixels readfrom RAM to avoid the restriction on only one access per RAM per clockcycle. Without these variables, the condition for the if statement wouldrequire multiple accesses to the Source RAM.

[0769] 5. The pixel values may be extended by one bit to ensure thesubtract does not underflow.

[0770] 6. The Input and Output channels are declared to read from andwrite to files for simulation. The file name is given using the withspecification, e.g. chanin unsigned Input with{infile=“../Data/source.dat”};

[0771] To Execute the Handel-C Code:

[0772] 1. Convert the example BMP file to text data with the bmp2rawutility by typing:

[0773] bmp2raw source.bmp source.dat 8bppdest.rgb

[0774] 2. Open the Handel-C edge detector workspace(Examples/Handel-C/Examples/ExampleC/ExampleC.hw) by double-clicking onit. Build and run the project.

[0775] 3. Convert the output from the edge detector back to a BMP fileusing the raw2bmp utility by typing:

[0776] raw2bmp 256 dest.dat dest_v1.bmp 8bppsrc.rgb. Example codeversion1 /**************************************************************** * Description * * Handel-C edge detector example program - Firstpass. * * * * To test open the workspace file ‘ExampleC.hw’. * * ************************************************************* ***** / * *Define a clock */ set clock = external “P1”; /* * Define parameters ofimage and threshold for edges */ #define LOG2_WIDTH 8 #define WIDTH 256#define LOG2_HEIGHT 8 #define HEIGHT 256 #define THRESHOLD 16 /* *Declare RAMs for source and destination images */ ram unsigned charSource [WIDTH*HEIGHT]; ram unsigned char Dest [WIDTH*HEIGHT]; /* *Declare a macro for absolute value */ macro expr abs(a) = (a<0 ? −a :a); /* * Edge detector procedure */ void edge_detect() { unsigned(LOG2_WIDTH+LOG2_HEIGHT) x; unsigned (LOG2_WIDTH+LOG2_HEIGHT) y; int 9Pixel1, Pixel2, Pixel3; /* * Loop round for every pixel */ for (y=1;y<HEIGHT; y++) { for (x=1; x<WIDTH; x++) { Pixel1=(int) (0 @ Source[x +y*WIDTH]); Pixel2=(int) (0 @ Source[x−1 + y*WIDTH]); Pixel3=(int) (0 @Source[x + (y−1) *WIDTH]); /* * Determine whether there is an edge here*/ if (abs(Pixel1 − Pixel2) > THRESHOLD || abs (Pixel1 − Pixel3) >THRESHOLD) { Dest[x + y*WIDTH]=0xFF; } else { Dest[x + y*WIDTH]=0; } } }} /* * Main program */ void main(void) { chanin unsigned Input with{infile = “../Data/source.dat”}; chanout unsigned Output with {outfile =“../Data/dest.dat”}; unsigned (LOG2_WIDTH+LOG2_HEIGHT) i; unsigned(LOG2_WIDTH+LOG2_HEIGHT) j; /* * Read image from file */ for (i=0;i<HEIGHT; i++) for (j=0; j<WIDTH; j++) Input ? Source [j + i*WIDTH];/* * Do edge detection */ edge_detect(); /* * Write results back to file*/ for (i=0; i<HEIGHT; i++) for (j=0; j<WIDTH; j++) Output ! Dest[j +i*WIDTH]; delay; }

[0777] First Optimizations of the Handel-C Program

[0778] The next development stage is to change some of the operatorsfamiliar in C to operators more suitable for Handel-C. In the aboveexample, every time the Source or Dest RAM is accessed, a multiplicationis made by the constant WIDTH. The Handel-C optimizer simplifies this toa shift left by 8 bits but one could easily do this by hand to reflectthe hardware more accurately and reduce compilation times. New macrosmay also be introduced to access the RAMs given x and y co-ordinates:

[0779] macro expr ReadRAM(a, b)=

[0780] ((unsigned 1)0) @

[0781] Source[(0@a)+((0@b)<<8)];

[0782] macro proc WriteRAM(a, b, c)

[0783] Dest[(0@a)+((0@b)<<8)]=c;

[0784] Notice how the macros pad both the result and the co-ordinateexpressions with zeros. This allows one to reduce the width of the x andy counters to 8 bits each and reduces clutter in the rest of theprogram. This width reduction does mean that the loop conditions may bealtered because x and y are no longer wide enough to hold the constant256. Instead, one could test against zero since the counters may wrapround to zero after 255.

[0785] The modified edge_detect function is shown below:

[0786] Example code version 2

[0787] void edge_detect ( )

[0788] {

[0789] unsigned LOG2_WIDTH x;

[0790] unsigned LOG2_HEIGHT y;

[0791] int 9 Pixel1, Pixel2, Pixel3;

[0792] /*

[0793] * Loop round for every pixel

[0794] */

[0795] for (y=1; y!=0; y++)

[0796] {

[0797] for (x=1; x!=0; x++)

[0798] {

[0799] Pixel1=(int)ReadRAM(x, y);

[0800] Pixel2=(int)ReadRAM(x−1, y);

[0801] Pixel3=(int)ReadRAM(x, y−1);

[0802] /*

[0803] *Determine whether there is an edge here

[0804] */

[0805] if (abs(Pixel1-Pixel2)>THRESHOLD ||

[0806] abs(Pixel1-Pixel3)>THRESHOLD)

[0807] WriteRAM(x, y, 0xFF);

[0808] else

[0809] WriteRAM(x, y, 0);

[0810] }

[0811] }

[0812] To execute this version of the Handel-C code:

[0813] 1. Make the version 2 project current within the ExampleCworkspace by selecting Project>Set Active Project>Edge_v2:

[0814] 2. Build and run the project by selecting Build>Build Edge_v2followed by F5.

[0815] 3. Convert the output from the edge detector back to a BMP fileusing the raw2bmp utility by opening a Command Prompt or MS-DOS window.Change to the Version 2 project directory and type: raw2bmp 256 dest.datdest_v2.bmp 8bppsrc.rgb

[0816] Adding Fine Grain Parallelism

[0817] There are two areas in this program that can be modified toimprove performance. The first is to replace for loops with while loopsand the second solves the problem of multiple accesses to external RAMin single clock cycles.

[0818] The for loop expands into a while loop inside the compiler in thefollowing way:

[0819] for (Init; Test; Inc)

[0820] Body;

[0821] becomes:

[0822] {

[0823] Init;

[0824] while ( Test)

[0825] {

[0826] Body;

[0827] Inc;

[0828] }

[0829] }

[0830] This is normally not efficient for hardware implementationbecause the Inc statement is executed sequentially after the loop bodywhen in most cases it could be executed in parallel. The solution is toexpand the for loops by hand and use the par statement to execute theincrement in parallel with one of the statements in the loop body.

[0831] The second optimization concerns the three statements required toread the three pixels from external RAM. Without the restriction onmultiple accesses to RAMs the loop body of the edge detector could beexecuted in a single cycle whereas our current program requires fourcycles, three of which access the RAM. What is needed is a modificationto eliminate as many of these RAM accesses as possible.

[0832] Since it is not possible to access the external RAM more thanonce in one clock cycle, the only way to improve this program is toaccess multiple RAMs in parallel. It should also be clear that thecurrent program accesses most locations in the external RAM three times.For example, when x is 34 and y is 56 the three pixels read are atco-ordinates (34,55), (33,56) and (34,56).

[0833] The first of these is also read when x is 34 and y is 55 and whenx is 35 and y is 55 whereas the second is also read when x is 33 and yis 56 and when x is 33 and y is 57. If one can devise a scheme wherebypixels are stored in two extra RAMs when they are read from the mainexternal RAM for the first time then they could simply access theseadditional RAMs to get pixel values in the main loop.

[0834] The first step is to store the previous line of the image in aninternal RAM on the FPGA. This allows the pixel above the currentlocation to be read at the same time as the external RAM is accessed.The second step is to store the pixel to the left of the currentlocation in a register. The loop body then looks something like this:

[0835] Pixel1=ReadRAM(x, y);

[0836] Pixel2=PixelLeft;

[0837] Pixel3=LineAbove[x];

[0838] LineAbove[x]=Pixel1;

[0839] PixelLeft=Pixel1;

[0840] At first glance, it looks like things have been worse byincreasing the number of clock cycles but one can now add parallelism tomake it look like this:

[0841] par

[0842] {

[0843] Pixel1=(int)ReadRAM(x, y);

[0844] Pixel2=PixelLeft;

[0845] Pixel3=(int)LineAbove[x];

[0846] }

[0847] par

[0848] {

[0849] LineAbove[x]=Pixel1;

[0850] PixelLeft=Pixel1;

[0851] }

[0852] Note the LineAbove RAM may be initialized at the start of theimage to contain the first line of the image and the PixelLeft variablemay be initialized at the start of each line with the left hand pixel onthat line. Since the second of these par statements and the if statementare not dependent on each other they can be executed in parallel.Putting all these modifications together gives an edge_detect procedureshown below.

[0853] Notice that the increment of y has been moved from the end of theloop to the start and the start and end values have been adjustedaccordingly. This allows the increment to be executed without additionalclock cycles which would have been required if it were placed at the endof the loop.

[0854] To execute this version of the Handel-C code:

[0855] 1. Make the version 3 project current within the ExampleCworkspace by selecting Project>Set Active Project>Edge_v3;

[0856] 2. Build and run the project by selecting Build>Build Edge_v3followed by F5.

[0857] 3. Convert the output from the edge detector back to a BMP fileusing the raw2bmp utility by opening a Command Prompt or MS-DOS window.Change to the Version 3 project directory and type: raw2bmp 256 dest.datdest_v3.bmp 8bppsrc.rgb

[0858] Example code version 3

[0859] void edge_detect( )

[0860] {

[0861] unsigned LOG2 WIDTH x;

[0862] unsigned LOG2_HEIGHT y;

[0863] int 9 Pixel1, Pixel2, Pixel3, PixelLeft;

[0864] ram LineAbove[ ];

[0865] /*

[0866] * Initialise the LineAbove RAM

[0867] */

[0868] x=1;

[0869] while (x!=0)

[0870] {

[0871] par

[0872] {

[0873] LineAbove[x]=ReadRAM(x, (unsigned LOG2_HEIGHT)0);

[0874] x++;

[0875] }

[0876] }

[0877] /*

[0878] * Loop for every line

[0879] */

[0880] y=0;

[0881] while (y!=255)

[0882] {

[0883] /*

[0884] * Initialise the PixelLeft register

[0885] */

[0886] par

[0887] {

[0888] x=1;

[0889] PixelLeft=(int)ReadRAM((unsigned LOG2_WIDTH)0, y+1);

[0890] y++;

[0891] }

[0892] /*

[0893] * Loop for every column

[0894] */

[0895] while (x !=0)

[0896] {

[0897] /*

[0898] * Update pixel registers

[0899] */

[0900] par

[0901] {

[0902] Pixel1=(int)ReadRAM(x, y);

[0903] Pixel2=PixelLeft;

[0904] Pixel3=(int)LineAbove[x];

[0905] }

[0906] /*

[0907] * Determine whether there is an edge here

[0908] */

[0909] par

[0910] {

[0911] LineAbove[x]=(unsigned)Pixel1;

[0912] PixelLeft=Pixel1;

[0913] if (abs(Pixel1-Pixel2)>THRESHOLD ||

[0914] abs(Pixel1-Pixel3)>THRESHOLD)

[0915] WriteRAM (x, y, 0XFF);

[0916] else

[0917] WriteRAM(x, y, 0);

[0918] x++;

[0919] }

[0920] }

[0921] Further Fine Grain Parallelism

[0922] The core loop body has now been reduced from five clock cycles(including the loop increment) to 2 clock cycles. One can even do betterbecause one should be able to access the two off-chip banks of RAM inparallel. Thus, the two parallel statements in the loop body could beexecuted simultaneously if one could organize the data flow correctly.

[0923] The program has been modified because the LineAbove internal RAMis accessed in both clock cycles. Paralleling the two statements is notpermitted because it would involve two accesses to the same internal RAMin a single clock cycle. The solution is to increase the number ofinternal RAMs. The current line can be copied into one internal RAMwhile the previous line is read from a second internal RAM. The twointernal RAM banks can then be swapped for the next line.

[0924] By also removing the Pixel1, Pixel2 and Pixel3 intermediatevariables, the two statements in the loop body can be rolled into one. Aperson may use the LSB of the y coordinate to determine which linebuffer to read from and which line buffer to write to. The external RAMread is done using a shared expression (RAMPixel) since one needs thevalue from the RAM in multiple places but only want to perform theactual read once.

[0925] The new version of the edge detector is shown below. The coreloop is now only one clock cycle long and is executed 255 times perline. One extra clock cycle is required per line for the initializationof variables and 255 lines are processed. In addition, 255 cycles arerequired to initialize the on-chip RAM and one extra clock cycle perframe is required for variable initialization. This gives a grand totalof 65536 clock cycles per frame or an average of exactly one pixel perclock cycle. Since there is no way of getting the image into or theresults out from the FPGA any faster than this one can conclude that thefastest possible solution to our problem has been reached.

[0926] Example code version 4

[0927] void edge_detect( )

[0928] {

[0929] unsigned LOG2_WIDTH x;

[0930] unsigned LOG2_HEIGHT y;

[0931] int 9 PixelLeft;

[0932] ram unsigned char LineAbove0[ ], LineAbove1 [ ];

[0933] unsigned 5 i;

[0934] /*

[0935] * Initialise the x and y counters and the LineAbove RAM

[0936] */

[0937] par

[0938] {

[0939] x=1;

[0940] y=0;

[0941] }

[0942] while (x!=0)

[0943] {

[0944] par

[0945] {

[0946] LineAbove0[x]=ReadRAM(x, (unsigned LOG2_HEIGHT)0)<−8;

[0947] x++;

[0948] }

[0949] }

[0950] /*

[0951] * Loop for every line

[0952] */

[0953] while (y!=255)

[0954] {

[0955] /*

[0956] * Initialise the PixelLeft register

[0957] */

[0958] par

[0959] {

[0960] x=1;

[0961] PixelLeft=(int)ReadRAM((unsigned LOG2_WIDTH)0, y+1);

[0962] y++;

[0963] }

[0964] /*

[0965] * Loop for every column

[0966] */

[0967] while (x !=0)

[0968] {

[0969] par

[0970] {

[0971] shared expr RAMPixel=(int)ReadRAM(x, y);

[0972] shared expr PixelAbove=(int)(y[0]==0 ? 0@LineAbove0[x]:

[0973] 0@LineAbove1[x]);

[0974] macro expr abs(a)=(a<0?−a : a);

[0975] /*

[0976] * Update pixel registers

[0977] */

[0978] if (y[0]==1)

[0979] LineAbove0[x]=(unsigned)(RAMPixel<−8);

[0980] else

[0981] LineAbove1[x]=(unsigned)(RAMPixel<−8);

[0982] PixelLeft=RAMPixel;

[0983] /*

[0984] * Determine whether there is an edge here

[0985] */

[0986] if (abs(RAMPixel-PixelLeft)>THRESHOLD ||

[0987] abs (RAMPixel-PixelAbove)>THRESHOLD)

[0988] WriteRAM(x, y, 0xFF);

[0989] else

[0990] WriteRAM(x, y, 0);

[0991] x++;

[0992] }

[0993] }

[0994] }

[0995] }

[0996] To execute this version of the Handel-C code:

[0997] 1. Make the version 4 project current within the ExampleCworkspace by selecting Project>Set Active Project>Edge_v4:

[0998] 2. Build and run the project by selecting Build>Build Edge_v4followed by F5

[0999] 3. Convert the output from the edge detector back to a BMP fileusing the raw2bmp utility by opening a Command Prompt or MS-DOS window.Change to the Version 4 project directory and type: raw2bmp 256 dest.datdest_v4.bmp 8bppsrc.rgb

[1000] Adding the Hardware Interfaces

[1001] Once the program has been simulated correctly one may add thenecessary hardware interfaces. The interface with the host requires thesame signals and timings as the example set out hereinafter. The codewill now be taken from that example and used to produce two macroprocedures—one to read a word from the host and one to write a word tothe host. (These could also be implemented as functions) The suitablymodified code looks like this:

[1002] // Read word from host

[1003] macro proc ReadWord(Reg)

[1004] {

[1005] while (ReadReady==0);

[1006] Read=1; // Set the read strobe

[1007] par

[1008] {

[1009] Reg=dataB.in; // Read the bus

[1010] Read=0; // Clear the read strobe

[1011] }

[1012] }

[1013] // Write one word back to host

[1014] macro proc Writeword(Expr)

[1015] {

[1016] par

[1017] {

[1018] while (WriteReady==0);

[1019] dataBOut=Expr;

[1020] }

[1021] par

[1022] {

[1023] En=1; // Drive the bus

[1024] Write=1; // Set the write strobe

[1025] }

[1026] Write=0; // Clear the write strobe

[1027] En=0; // Stop driving the bus

[1028] }

[1029] One also needs to define the pins for the external RAMs andremove the RAM declarations added to simulate the RAMs. The main programalso needs to be modified to include the code to synchronies the framegrabber with the edge detector. The project settings need to be changedin the GUI. Set the configuration to VHDL or EDIF. This code is notdesigned for a specific device. One would need to know the appropriatepins for the device one are targeting. The pin definitions given areexamples only and do not reflect the actual pins available on anyparticular device. The code excluding the edge detection and hostinterface macros is given below.

[1030] #define LOG2_WIDTH 8

[1031] #define WIDTH 256

[1032] #define LOG2_HEIGHT 8

[1033] #define HEIGHT 256

[1034] set clock=external “P1”;

[1035] unsigned 8 Threshold;

[1036] // External RAM definitions/declarations

[1037] ram unsigned 8 Source[65536] with {

[1038] offchip=1,

[1039] data={“P1”, “P2”, “P3”, “P4”,

[1040] “P5”, “P6”, “P7”, “P8”},

[1041] addr={“P9”, “P10”, “P11”, “P12”,

[1042] “P13”, “P14”, “P15”, “P16”,

[1043] “P17”, “P18”, “P19”, “P20”,

[1044] “P21”, “P22”, “P23”, “P24”},

[1045] we={“P25”}, oe={“P26”}, cs={“P27”}};

[1046] ram unsigned 8 Dest[65536] with

[1047] offchip=1,

[1048] data={“P28”, “P29”, “P30”, “P31”,

[1049] “P32”, “P33”, “P34”, “P35”},

[1050] addr={“P36”, “P37”, “P38, ”, “P39”,

[1051] “P40”, “P41”, “P41”, “P43”,

[1052] “P44”, “P45”, “P46”, “P47”,

[1053] “P48”, “P49”, “P50”, “P51”},

[1054] we={“P52”}, oe={“P53”}, cs=(“54”}};

[1055] macro expr ReadRAM(a, b)=

[1056] ((unsigned 1)0) @ Source[(0@a)+((0@b)<<8)];

[1057] macro proc WriteRAM(a, b, c) Dest [(0@a)+((0@b)<<8)]=c;

[1058] #ifndef SIMULATE

[1059] // Host bus definitions/declarations

[1060] unsigned 8 dataBOut;

[1061] int 1 En=0;

[1062] interface bus_ts_clock_in(int 4) dataB(dataBOut, En==1) with

[1063] (data={“P55”, “P56”, “P57”, “P58”}};

[1064] int 1 Write=0;

[1065] interface bus_out( ) writeB(Write) with

[1066] (data={“P59”}};

[1067] int 1 Read=0;

[1068] interface bus_out( ) read(Read) with

[1069] (data={“P60”}};

[1070] interface bus_clock_in(int 1) WriteReady( ) with

[1071] (data={“P61”}};

[1072] interface bus_clock_in(int 1) ReadReady( ) with

[1073] {data={“P62”}};

[1074] #endif

[1075] Insert edge_detect, ReadWord and WriteWord function and macro

[1076] definitions here

[1077] void main(void)

[1078] {

[1079] Readword(Threshold);

[1080] while(1)

[1081] {

[1082] unsigned Dummy;

[1083] ReadWord(Dummy);

[1084] edge_detect( );

[1085] WriteWord (Dummy);

[1086] }

[1087] Summary

[1088] The aim of this section has been to show the development of areal Handel-C program from conventional C to a full program targeted athardware. Is has also shown the performance benefits of the Handel-Capproach by demonstrating a real time application executing with a greatdeal of parallelism.

Targeting Hardware

[1089] Targeting Hardware via VHDL

[1090] If one is integrating Handel-C code with raw VHDL code, one wouldcompile the Handel-C for debug, and use ModelSim to compile the VHDL forsimulation. One could then compile the Handel-C to VHDL and use SimplifyLeonardoSpectrum or FPGA Express to synthesize the code. One would thenuse Xilinx or Altera tools to place and route it.

[1091] Linking to the Handel-C VHDL Library

[1092] The HandelC.vhdl file may be supplied which supports all Handel-CVHDL files. To use Handel-C VHDL, one may compile the HandelC.vhdl fileinto a library called HandelC. (Consult the documentation for thesynthesis or simulation tool on compiling library files.) A person alsoneeds to compile the supplied file ROC.vhdl into the work library forsimulation.

[1093] Connecting Handel-C EDIF to VHDL

[1094] If one compiles a Handel-C file to EDIF and wish to connect it toa VHDL, he or she may be aware that the ports in EDIF and VHDL aredifferent. EDIF ports consist of a collection of single wires. VHDLports are normally described as n-bit wide cables. To ensure that thegenerated EDIF can connect to the VHDL, the VHDL ports may be listed assingle-bit wires.

[1095] VHDL Component Within Handel-C Project

[1096] Handel-C Code

[1097] set clock=external “D17”;

[1098] unsigned 4 x;

[1099] interface vhdl_component(unsigned 4 return_val)

[1100] vhdl_component_instance(unsigned 1 clk=_clock,

[1101] unsigned 4 sent_value=x);

[1102] etc . . .

[1103] unsigned 4 y;

[1104] y=vhdl_component_instance; // Read from VHDL component

[1105] x=y; // Write to VHDL component

[1106] VHDL Code

[1107] The VHDL entity may need an interface like this to be compatiblewith the Handel-C.

[1108] entity vhdl_component is

[1109] port (

[1110] clk in std_logic;

[1111] sent_value_(—)0 : in std_logic;

[1112] sent_value_(—)1 : in std_logic;

[1113] sent_value_(—)2 : in std_logic;

[1114] sent_value_(—)3 : in std_logic;

[1115] return_val_(—)0 : out std_logic;

[1116] return_val_(—)1 : out std_logic;

[1117] return_val_(—)2 : out std_logic;

[1118] return_val_(—)3 : out std_logic

[1119] );

[1120] end;

[1121] Note that all the ports are 1-bit wide, standard_logic types.This is because when the Handel-C is compiled to EDIF, this is how theexpanded interface appears. (EDIF cannot represent n-bit wide cables,only single wires).

[1122] Handel-C Component Within VHDL Project

[1123] The Handel-C needs to have ports to its top level, so that theVHDL can connect to them.

[1124] unsigned 4 x;

[1125] interface port_in(unsigned 1 clk) ClockPort( );

[1126] interface port_in(unsigned 4 sent_value) InPort( );

[1127] interface port_out( ) OutPort(unsigned 4 return_value=x);

[1128] set clock=internal ClockPort.clk;

[1129] etc . . .

[1130] unsigned 4 y;

[1131] y=InPort.sent_value; // Read from top-level VHDL

[1132] x=y; // Write to top-level VHDL

[1133] VHDL code

[1134] The top level VHDL may need to instantiate the Handel-C like

[1135] this:

[1136] component handelc_component

[1137] port (

[1138] clk : out std_logic;

[1139] sent_value_(—)0 : out std_logic;

[1140] sent_value_(—)1 : out std_logic;

[1141] sent_value_(—)2 : out std_logic;

[1142] sent_value_(—)3 : out std_logic;

[1143] return_val_(—)0 : in std_logic;

[1144] return_val_(—)1 : in std_logic;

[1145] return_val_(—)2 : in std_logic;

[1146] return_val_(—)3 : in std_logic

[1147] );

[1148] end component;.

[1149] Targeting Hardware via EDIF

[1150] To target hardware via EDIF, one may set up the project to targetEDIF using the Build>Set Active Configuration command. This compilesdirectly to an .edf file which can be passed to the place and routetools.

[1151] Port Renaming for Debug

[1152] To aid in debugging the generated EDIF, one can rename the EDIFnets within the net list such that the Handel-C declaration name appearsbefore the EDIF unique identifier.

[1153] To do so, select the Project>Settings . . . command. In theProject Settings dialog that opens, ensure that the EDIF is the type ofsettings that is being edited.

[1154] In the Compiler tab, check the Generate debug information box.

[1155] Setting Up Place and Route Tools

[1156]FIG. 35 illustrates a net list reader settings display 3500, inaccordance with one embodiment of the present invention. The Altera EDIFcompiler requires a library mapping file. This is supplied ashandelc.lmf.

[1157] Setting Up MaxPlus II to Use handelc.lmf

[1158] Start MaxPlus II

[1159] Open MaxPlus II>Compiler

[1160] With the compiler selected, select Interface>EDIF Net list ReaderSettings.

[1161] In the dialog box, specify Vendor as Custom.

[1162] Click the Customize>>button (3502)

[1163] Select the LMF #1 radio button (3504). Set up the pathname (3506)for the handelc.lmf file.

[1164] (Installed in Handel-C installation root\lmf.)

[1165] Setting Up Quartus 2000 to Use handelc.lmf

[1166]FIGS. 36 and 37 illustrates a tool settings display 3600 and 3700,in accordance with one embodiment of the present invention.

[1167] Start Quartus.

[1168] Select the Project>EDA Tool Settings menu command.

[1169] In the dialog box, use the pull-down list to set Custom as theDesign entry/synthesis tool..

[1170] Click Settings. (3602) (Note FIG. 37.)

[1171] Set the File name 3702 for the Library Mapping File, click the .. . button to browse for handelc.lmf. (Installed in Handel-Cinstallation root\lmf)

[1172] Setting Up Wire Names

[1173] One can specify the format of floating wire names in EDIF usingthe Handel-C bus format specification. This allows one to use theformats B1 B_(—)1 B[1] B(1)

[1174] where B represents the bus name, and 1 the wire number.

[1175] interface port_in(int 4 signals_to_HC with

[1176] {busformat=“B[1}) read( );

[1177]FIG. 38 illustrates the wires 3800 that would be produced whenspecifying floating wire names, in accordance with one embodiment of thepresent invention.

Connecting to VHDL Blocks

[1178] Requirements

[1179] If one wishes to connect Handel-C code to VHDL blocks andsimulate the results, one may require the following objects:

[1180] A VHDL simulator (currently ModelSim)

[1181] The cosimulator plugin (e.g. PlugInModelSim.dll) to allow theVHDL simulator to work in parallel with the Handel-C simulator. Thisfile is provided with the copy of Handel-C

[1182] The file plugin.vhdl to connect the VHDL to the cosimulatorplugin. This file is included with the copy of Handel-C

[1183] A VHDL wrapper file to connect the VHDL entity ports to theHandel-C simulator and to VHDL dummy signals. (One may write this)

[1184] The VHDL entity and architecture files (one may provide or writethese)

[1185] A Handel-C code file that includes an interface definition in theHandel-C code to connect it to the VHDL code. (One may write this.)

[1186] Simulation Requirements

[1187] Before one can simulate the code he or she may:

[1188] 1. Set up ModelSim so that the work library refers to the librarycontaining this wrapper component.

[1189] 2. Check that the plugin has been installed in the same place asthe other Handel-C components. If one has moved it, he or she may ensurethat its new location is on the PATH.

[1190] 3. Compile the VHDL model to be integrated with Handel-C into theVHDL simulator.

[1191] 4. Compile plugin.vhdl.

[1192] 5. Compile the wrapper.

[1193] 6. Compile the Handel-C code and run the Handel-C simulator Thismay invoke any VHDL simulations required.

[1194] Batch Files

[1195] Sample batch files that carry out these tasks have been suppliedwith the examples:

[1196] handelc_vhdl.bat Sets up environment variables for ModelSim. Runonce before first co-simulating

[1197] reg32x1k_vhdl.bat Compiles all the components for the registerexample. Run once before co-simulating the example. Run again if theVHDL code is changed

[1198] ttI7446_vhdl.bat Compiles all components for the combinatoriallogic example. Run before co-simulating and if the VHDL code is changed.

[1199]FIG. 39 illustrates an interface 3900 in the form of a plug-in3902 between Handel-C 3904 and VHDL 3906 for simulation, in accordancewith one embodiment of the present invention.

[1200] Place and Route Requirements

[1201] If one wishes to compile the Handel-C code and VHDL blocks andplace and route the results, he or she may need to:

[1202] Compile the Handel-C code to VHDL.

[1203] Pass the compiled Handel-C and the VHDL model to an RTL synthesistool (such as FPGAExpress).

[1204] Run the place and route.

[1205] Writing Handel-C to Communicate with VHDL

[1206] The code needed in the Handel-C program is in two parts. First,one needs an interface declaration. This prototypes the interface sortand is of the format:

[1207] Interface

[1208] VHDL_entity_sort (VHDL_to_HC_port

[1209] {,VHDL_to_HC_port})

[1210] (VHDL_from_HC_port

[1211] {, VHDL_from_HC_port});

[1212] where:

[1213] VHDL_entity_sort is the name of the VHDL entity. This name may beused as the interface sort.

[1214] VHDL_to_HC_port is the type and name of a port bringing data tothe Handel-C code (output from VHDL) precisely as specified in theunwrapped VHDL entity

[1215] VHDL_from_HC_port is the type and name of a port sending datafrom the Handel-C code (input to VHDL) precisely as specified in theunwrapped VHDL entity.

[1216] Note that ports are seen from tie VHDL side, so port names may beconfusing. In Handel-C, the ports that input data TO the Handel-C may bespecified first.

[1217] One then needs an interface definition. This creates an instanceof that interface sort, and defines the data that may be transmitted.This is of the format:

[1218] Interface

[1219] VHDL_entity_sort (VHDL_to_HC_port [with portSpec]

[1220] {, VHDL_to_HC_port [with portSpec]})

[1221] interface_Name (VHDL_from_HC_data=from_HC_data

[1222] [with portSpec]

[1223] {, VHDL_from_HC_data=from_HC_data

[1224] [with portSpec]})

[1225] with {extlib=“PluginModelSim.dll”,

[1226] extinst=“instanceName; model=entity_wrapper;

[1227] clock=clockName:period; delay=units”});

[1228] where:

[1229] VHDL_entity_sort is the interface sort that one previouslydeclared.

[1230] VHDL_to_HC_port is the type and name of a port bringing data tothe Handel-C code (output from VHDL). This may have the same type asdefined in the interface declaration

[1231] interface_Name is the name for this instance of the interface.

[1232] VHDL_from_HC_port is the type and name of a port sending datafrom the Handel-C code (input to VHDL). This may have the same type asdefined in the interface declaration

[1233] VHDL_from_HC_data is an expression that is output from theHandel-C to the VHDL.

[1234] with portSpec is an optional port specification. FIGS. 40A and40B illustrate a table of possible specifications 4000, in accordancewith one embodiment of the present invention. The with list after theport listings gives the specifications for all the ports on theinstance. These general specifications may be overruled by anyindividual port specifications.

[1235] extlib=“PluginModelSim.dll” specifies the cosimulator used. Theextinst string gives the parameters to the cosimulator plugin. Theparameters for PluginModelSim.dll are as follows:

[1236] instanceName is a unique name representing that instance of theVHDL entity. It is recommended that this is the same as theinterface_Name.

[1237] entity wrapper is the name of the VHDL wrapper component.

[1238] clock—clockName: period is only needed in clocked circuits. Itdefines the port and period of the clock input to the VHDL fromHandel-C. clockName is the name of the port that carries the clocksignal. period is the number of simulator time units per clock tick. Thesimulation time in ModelSim is advanced by this time delay every clockcycle.

[1239] delay=units is optional. It gives the combinational delay to beused by the simulator to allow a combinational input to propagate to anoutput. For zero delay models as used in RTL synthesis, a single timeunit is all that is required. The default value is 1.

[1240] ModelSim may be automatically started when the Handel-C model isrun and may be automatically closed when the Handel-C model is closed.Error messages relating to the VHDL model may appear in the ModelSimmessage window, but may also be reflected back to the Handel-C debugwindow.

[1241] Clocked Circuit Simulation

[1242] The simulator time units are determined by ModelSim'spreferences, which may be found in a modelsim.ini file in the localdirectory. (It is created on first use of the simulator in anydirectory—one can then edit it to modify the settings). The default timeunit is ns. If one has the values: clock=ck:25; delay=1. Clock risingedges may occur at 25 ns, 50 ns, 75 ns and the outputs may be sampled at26 ns, 51 ns, 76 ns and so on. Clocks are assumed to have equalmark:space ratios. However, ModelSim can only deal with delays that areintegral multiples of the time unit. If the period is odd (as in thiscase), the high time may be shorter than the low time, so in this casethe clock may have a 12:13 ratio.

[1243] Interfacing the VHDL with the Handel-C Simulator

[1244]FIG. 41 illustrates the use of various VHDL files 4100, inaccordance with one embodiment of the present invention. One needs toprovide a wrapper file 4102 for VHDL code 4104. The wrapper file wrapsthe VHDL code, connecting the entity ports to dummy signals and providesthe interface to the Handel-C simulator plugin 4106. The wrapper code isonly required in the simulation phase, not in the synthesis phase. Thefollowing information assumes that one has two VHDL files, the objectcode for the architecture file (entity₁₃ architecture.vhdl) and thesource code for the interface to the behavior file (entity.vhdl).

[1245] One needs to examine the ports defined in the entity file, andensure that each port is connected to a signal in a wrapper file. Asample wrapper file is provided. It assumes that the plugin, entity andwrapper file have all been compiled to the default work library.

[1246] entity name_wrapper is

[1247] end;

[1248] --do standard library stuff

[1249] library ieee;

[1250] use ieee.std_logic_(—)1164.all;

[1251] use ieee.std_logic_arith.all;

[1252] architecture top_level of name_wrapper is

[1253] signal name : type;

[1254] (repeat as necessary)

[1255] begin

[1256] pluginName:entity work.plugin; --connect to Handel-C link

[1257] entityName: entity work.entity port map (signal_names);

[1258] end;

[1259] To use the file, replace the sections in italics as follows namewrapper replace with the appropriate wrapper name.

[1260] entity_wrapper is recommended.

[1261] signal name:type; replace with a list of dummy signals thatconnect to the entity ports for compilation purposes. These signals canhave any name, but the format and order of the ports may be exactly asspecified in the VHDL

[1262] pluginName is a user-defined name for that instance of the pluginthat connects the signals through the simulators

[1263] entityName is a user-defined name for that instance of the entity

[1264] signalNames is a comma-separated list of the dummy signals.

[1265] Note that a limited number of port types are supported:

[1266] 1-bit types in Handel-C may be implemented by std_logic

[1267] n-bit unsigned and signed types in Handel-C may be implemented bystd_logic_arith.unsigned

[1268] No other types may be used. If the circuit uses other types onemay need to create another VHDL wrapper containing type conversions tothese three types between the plugin wrapper and the circuit to beintegrated.

[1269] Example

[1270] The following example shows the code for a trivial VHDL entityfile simple.vhdl. This describes the interface for the simplearchitecture.

[1271] library ieee;

[1272] use ieee.std_logic_(—)1164.all;

[1273] use ieee.std_logic_arith.all;

[1274] entity simple is

[1275] port (input : in unsigned(63 downto 0);

[1276] output : out unsigned(63 downto 0);

[1277] simtime : out unsigned(31 downto 0));

[1278] end;

[1279] architecture behavior of simple is

[1280] begin

[1281] process (input)

[1282] begin

[1283] output<=conv_unsigned(input*conv_unsigned(2,input′length),output′length);

[1284] simtime<=conv_unsigned(input, 32);

[1285] end process;

[1286] end;

[1287] Wrapper File

[1288] This shows the code for the wrapper file for simple.vhdl. Thisfile would be called simple_wrapper.vhdl.

[1289] entity simple_wrapper is

[1290] end;

[1291] library ieee;

[1292] use ieee.std_logic_(—)1164.all;

[1293] use ieee.std_logic_arith.all;

[1294] architecture top_level of simple_wrapper is

[1295] signal x : unsigned (63 downto 0);

[1296] signal z : unsigned (63 downto 0);

[1297] signal t : unsigned (31 downto 0);

[1298] begin

[1299] plugin1: entity work.plugin;

[1300] simple1: entity work.simple port map (x, z, t);

[1301] end,

[1302] Handel-C Code

[1303] This is the interface to the VHDL. Note that the interface sortis simple and the port names are identical to the input and outputentity names in the VHDL.

[1304] set clock=external “P1”;

[1305] unsigned 64 x;

[1306] interface simple(int 64 output, int 32 simtime)

[1307] t1(int 64 input=x) with

[1308] {extlib=“PluginModelSim.dll”,extinst=“simple_wrapper”};

[1309] void main(void)

[1310] {

[1311] unsigned 64 y;

[1312] unsigned 32 now;

[1313] x=1;

[1314] while(1)

[1315] {

[1316] par

[1317] {

[1318] y=t1.output; // set y to the vhdl output

[1319] now=t1.simtime; // and now to simtime

[1320] }

[1321] x=y;

[1322] }

[1323] Compiling and Simulating the examples

[1324] These examples are installed in the subdirectoryHandel-C\Examples\VHDL. There are two projects. Example1 contains thecombinatorial circuit and Example2 contains the registers example.Supplied with each example is a batch file that compiles the VHDL forModelSim. To run the examples one may set up ModelSim for interfacingwith Handel-C, compile the VHDL and compile the Handel-C.

[1325] Setting Up ModelSim

[1326] Go to the project directory and double click on the batch filehandelc_vhdl.bat to run it. This only has to be done once.

[1327] Compiling the VHDL

[1328] Double click the appropriate project batch file (ttl7446_vhdl.batfor the combinatorial logic project and reg32x1k_vhdl.bat for theregisters project). This compiles the VHDL. If one changes the VHDLcode, he or she may need to recompile it.

[1329] Compiling and Simulating the Handel-C

[1330] Double-click on the workspace file (e.g. Example1.hw) to startHandel-C. Click the Build button or select Build>Build to compile andbuild the example. Once it has built, select Debug>Go or Debug>Step Intoto start the simulation..Connecting to VHDL blocks

[1331] A Simple Combinatorial Circuit Example

[1332] The VHDL Code

[1333] The VHDL code for the combinatorial circuit is in the filett17446.vhdl

[1334] library ieee;

[1335] use ieee.std_logic_(—)1164.all;

[1336] use ieee_std_logic_arith.all;

[1337] entity TTL7446 is

[1338] port (ltn : in std_logic;

[1339] rbin : in std_logic;

[1340] digit : in unsigned(3 downto 0);

[1341] bin : in std_logic;

[1342] segments : out unsigned(0 to 6);

[1343] rbon : out std_logic);

[1344] end;

[1345] architecture behavior of TTL7446 is

[1346] begin

[1347] process(ltn, rbin, bin, digit)

[1348] begin

[1349] rbon<=‘1’;

[1350] if bin=‘0’ then

[1351] segments<=“1111111”;

[1352] elsif ltn=‘0’ then

[1353] segments<=“1000000”;

[1354] else

[1355] case digit is

[1356] when “0000” => segments<=“0000001”;

[1357] if rbin=‘0’ then

[1358] segments<=“1111111”;

[1359] rbon<=‘0’;

[1360] end if;

[1361] when “0001” => segments <=“1001111”;

[1362] when “0010” => segments <=“0010010”;

[1363] when “0011” => segments <=“0000110”;

[1364] when “0100” => segments <=“1001100”;

[1365] when “0101” => segments <=“0100100”;

[1366] when “0110” => segments <=“1100000”;

[1367] when “0111” => segments <=“0001111”;

[1368] when “1000” => segments <=“0000000”;

[1369] when “1001” => segments <=“0001100”;

[1370] when “1010” => segments <=“1110010”;

[1371] when “1011” => segments <=“1100110”;

[1372] when “1100” => segments <=“1011100”;

[1373] when “1101” => segments <=“0110100”;

[1374] when “1110” => segments <=“1110000”;

[1375] when “1111” => segments <=“1111111”;

[1376] when others => segments <=“XXXXXXX”;

[1377] end case;

[1378] end if;.

[1379] A Sample Wrapper for the Combinatorial Circuit

[1380] The VHDL wrapper code for the combinatorial circuit is in thefile ttl7446_wrapper.vhdl

[1381] entity TTL7446_wrapper is

[1382] end;

[1383] library ieee;

[1384] use ieee.std_logic_(—)1164.all;

[1385] use ieee.std_logic_arith.all;

[1386] architecture HandelC of TTL7446_wrapper is

[1387] signal ltn : std_logic;

[1388] signal rbin : std_logic;

[1389] signal digit : unsigned(3 downto 0);

[1390] signal bin : std_logic;

[1391] signal segments : unsigned(0 to 6);

[1392] signal rbon : std_logic;

[1393] begin

[1394] plugin1: entity work.plugin;

[1395] ttl: entity work.TTL7446 port map (ltn, rbin, digit, bin,

[1396] segments, rbon);

[1397] end;

[1398] This shows the two instances. It also shows each port of thecircuit to be integrated connected to a signal which is not connected toanything else. This is not a requirement of the plugin, but arequirement of VHDL. Note that VHDL′93 features have been used to createdirect instantiations of the components.

[1399] Example Handel-C Using the Combinatorial Circuit

[1400] This is in the file ttl7446_test.c

[1401] // Set chip details

[1402] set clock=external “D17”;

[1403] set part=“V1000BG560-4”;

[1404] // Interface declaration

[1405] interface TTL7446(unsigned 7 segments, unsigned 1 rbon)

[1406] (unsigned 1 ltn, unsigned 1 rbin, unsigned 4 digit,

[1407] unsigned 1 bin);

[1408] // Main program

[1409] void main(void)

[1410] {

[1411] unsigned 1 ltnVal;

[1412] unsigned 1 rbinVal;

[1413] unsigned 1 binVal;

[1414] unsigned 4 digitVal;.Connecting to VHDL blocks

[1415] unsigned 1 rbonVal;

[1416] unsigned 20 Delay;

[1417] interface TTL7446(unsigned 7 segments, unsigned 1 rbon)

[1418] decode(unsigned 1 ltn=ltnVal, unsigned 1 rbin=rbinVal,

[1419] unsigned 4 digit=digitVal, unsigned 1 bin=binVal)

[1420] with {extlib=“PluginModelSim_dll”,

[1421] extinst=“decode; model=TTL7446_wrapper; delay=1”};

[1422] interface bus_out ( ) display (unsigned display=˜decode.segments)

[1423] with {extlib=“7segment.dll”, extinst=“0”,

[1424] data={“AN28”, “AK25”, “AL26”, “AJ24”, “AM27”, “AM26”, “AK24”}};

[1425] par

[1426] {

[1427] ltnVal=0;

[1428] rbinVal 0;

[1429] binVal=0;

[1430] digitVal=0;

[1431] }

[1432] while (1)

[1433] {

[1434] binVal=1;

[1435] ltnVal=1;

[1436] do

[1437] {

[1438] do

[1439] {

[1440] rbonVal=decode.rbon;

[1441] digitVal++;

[1442] #ifndef SIMULATE

[1443] do { Delay++; } while(Delay!=0);

[1444] #endif

[1445] } while (digitVal !=0);

[1446] rbinVal++;

[1447] } while (rbinVal !=0);

[1448] }

[1449] Interface Code

[1450] One may declare an interface sort that has port names of the samename and type as the VHDL signals in the circuit to be integrated. Theinterface sort may be the same as the VHDL model's name.

[1451] interface TTL7446(unsigned 7 segments, unsigned 1 rbon) (unsigned1 ltn, unsigned 1 rbin, unsigned 4 digit, unsigned 1 bin);

[1452] An instance of this component is then created one or more timesin the Handel-C code. An example of an instantiation is:

[1453] interface TTL7446(unsigned 7 segments, unsigned 1 rbon)decode(unsigned 1

[1454] ltn=ltnVal, unsigned 1 rbin=rbinVal, unsigned 4 digit=digitVal,unsigned 1

[1455] bin=binVal) with {extlib=“PluginModelSim.dll”, extinst=“decode;

[1456] model=ttl7446_wrapper; delay=1”)};.Connecting to VHDL blocks

[1457] Simple Register Bank Circuit Example

[1458] VHDL Code

[1459] The VHDL code for the register bank circuit is in the filereg32x1k.vhdl

[1460] library ieee;

[1461] use ieee.std_logic_(—)1164.all;

[1462] use ieee.std_logic_arith.all;

[1463] entity reg32x1k is

[1464] -- simple synchronous register bank, 32 bits wide and 1k

[1465] registers deep

[1466] port(address : in unsigned(9 downto 0);

[1467] data_in : in unsigned(31 downto 0);

[1468] ck : in std_logic;

[1469] write : in std_logic;

[1470] data_out : out unsigned(31 downto 0));

[1471] end;

[1472] architecture behavior of reg32x1k is

[1473] type register_array is array (natural range <>) of unsigned(31

[1474] downto 0);

[1475] signal data : register_array(0 to 1023) :=(others=>(others=>

[1476] ‘0’));

[1477] begin

[1478] process (ck)

[1479] begin

[1480] if ck′event and ck=‘1’ then

[1481] if write=‘1’ then

[1482] data(conv_integer(address))<=data_in;

[1483] end if;

[1484] end if;

[1485] end process;

[1486] data_out <=data(conv_integer(address));

[1487] end;

[1488] VHDL Wrapper for Registers Example

[1489] This is the File reg32x1k_wrapper.vhdl.

[1490] entity reg32x1k_wrapper is

[1491] end;

[1492] library ieee;

[1493] use ieee.std_logic_(—)1164.all;

[1494] use ieee.std_logic_arith.all;

[1495] architecture HandelC of reg32x1k_wrapper is

[1496] signal address : unsigned(9 downto 0) :=(others => ‘0’);

[1497] signal data_in : unsigned(31 downto 0) :<=(others => ‘0’);

[1498] signal ck : std_logic :<=‘0’;

[1499] signal write : std_logic :=‘0’;

[1500] signal data_out : unsigned(31 downto 0) :<=(others => ‘0’);

[1501] begin

[1502] plugin1: entity work.plugin;

[1503] registers: entity work.reg32x1k port map (address, data_in, ck,

[1504] write, data_out);

[1505] end;

[1506] Handel-C Code to Interface With Registers

[1507] This is the file reg32x1k_test.c.

[1508] // Set chip details

[1509] set clock <=external “D17”;

[1510] set part <=“V1000DG560-4”;

[1511] // Interface declaration

[1512] interface reg32x1k(unsigned 32 data_out)

[1513] (unsigned 10 address, unsigned 32 data_in,

[1514] unsigned 1 ck, unsigned 1 write);

[1515] // Main program

[1516] void main(void)

[1517] {

[1518] unsigned 32 data_outVal;

[1519] unsigned 10 addressVal;

[1520] unsigned 32 data_inVal;

[1521] unsigned 1 writeVal;

[1522] interface reg32x1k(unsigned 32 data_out)

[1523] registers(unsigned 10 address=addressVal

[1524] with {extpath <={data_out}},

[1525] unsigned 32 data_in=data_inVal,

[1526] unsigned 1 ck <=_clock,

[1527] unsigned 1 write <=writeVal)

[1528] with {extlib=“PluginModelSim.dll”, extinst=“1; model=reg32x1kwrapper; clock=ck:25“};.Connecting to

[1529] VHDL blocks

[1530] par

[1531] {

[1532] addressVal <=0;

[1533] data inVal <=0;

[1534] writeVal <=0;

[1535] }

[1536] while(1)

[1537] {

[1538] par

[1539] {

[1540] writeVal <=1;

[1541] addressVal <=0;

[1542] }

[1543] do

[1544] {

[1545] par

[1546] {

[1547] addressVal++;

[1548] data_inVal +=10;

[1549] }

[1550] data_outVal <=registers.data_out;

[1551] } while (addressVal < 10);

[1552] par

[1553] {

[1554] writeVal <=0;

[1555] addressVal <=0;

[1556] }

[1557] do

[1558] {

[1559] addressVal++;

[1560] data_outVal <=registers.data_out;

[1561] } while (addressVal < 10);

[1562] }

Application Programmers Interface

[1563]FIG. 41A illustrates a method 4150 for equipping a simulator withplug-ins. In general, in operation 4152, a first simulator written in afirst programming language is executed for generating a first model.Further, in operation 4154, a second simulator written in a secondprogramming language is executed to generate a second model. In oneaspect, the first simulator may be cycle-based and the second simulatormay be event-based. More information on such types of simulators will beset forth hereinafter in greater detail during reference to FIG. 44A.

[1564] By this design, a co-simulation may be performed utilizing thefirst model and the second model. See operation 4156. In one aspect ofthe present invention, the accuracy and speed of the co-simulation maybe user-specified. In another aspect, the co-simulation may includeinterleaved scheduling.

[1565] In an additional aspect of the present invention theco-simulation may include fully propagated scheduling. In a furtheraspect, the simulations may be executed utilizing a plurality ofprocessors (i.e. a co-processor system). In even another aspect, thefirst simulator may be executed ahead of or behind the second simulator.In yet an additional aspect, the first simulator may interface with thesecond simulator via a plug-in. More information regarding suchalternate embodiments will be set forth hereinafter in greater detail.

[1566] The Application Programmers Interface (API) thus describes how towrite plugins to connect to the Handel-C simulator. Plugins are programsthat run on the PC and connect to a Handel-C clock or interface. Theycan be written in any language.

[1567] Examples of useful plugins are:

[1568] Simulated oscilloscope

[1569] Simulated wave-form generators

[1570] Selected display and storage of variables for debugging

[1571] Co-simulation of other circuits

[1572] Data Widths in the Simulator

[1573] The simulator uses 32-bit, 64-bit or arbitrary width arithmeticas appropriate. The interface to the simulator uses pointers to valuesof defined widths. Where 32 bit or 64 bit widths are used, data isstored in the most significant bits.

[1574] Simulator Interface

[1575] The plugin is identified to the simulator by:

[1576] the name of the compiled .dll (the compiled plugin)

[1577] the function calls that pass data between the plugin and theHandel-C program

[1578] the instance name

[1579] These are passed to the simulator using the with specifications

[1580] extlib Specifies the name of the DLL. No default.

[1581] extlib Specifies an instance string. No default.

[1582] extfunc Specifies the function to call to pass data to the pluginor get data from the plugin. Defaults to PlugInSet( ) for passing datato the plugin and PlugInGet( ) to get data from the plugin.

[1583] The simulator expects the plugin to support various functioncalls and some data structures. The simulator also has functions thatcan be called by the plugin (callback functions). These functions giveinformation about the state of variables in the Handel-C program. FIGS.42A and 42B illustrate various function calls 4200 and the various usesthereof, in accordance with one embodiment of the present invention.

[1584] Function Name Retention in C++

[1585] The simulator requires that the function names within the pluginare retained. Since C++ compilers may change function names one mayensure that the function names are identified as C types. To do so, onemay either compile the plugin as a C file, or, if he or she is compilingit as C++, he or she may use the extern extension to force the compilerto use the C naming convention. To compile the function as C++ place thestring extern “C” immediately before the function definition to ensurethat the function names are exported as written, e.g. extern “C”

[1586] dll void PlugInOpen(HCPLUGIN_INFO *Info, unsigned long NumInst)

[1587] {

[1588] // this function intentionally left blank

[1589] // initialising before the first simulation is run

[1590] Specifying Plugins in the Handel-C Source Code

[1591] Plugins are specified in the Handel-C source code using theextlib, extinst and extfunc specifications. These specifications may beapplied to clocks or interface definitions. For example:

[1592] set clock=external “P1” with {extlib=“plugin.dll”,extinst=“instance0”}; In the case of interface definitions, thespecifications may be specified for individual ports or for theinterface as a whole. For example:

[1593] interface bus_in(unsigned 4 Input) BusName( ) with

[1594] {extlib=“plugin.dll”, extinst=“some instance string”,

[1595] extfunc=“BusNameGetValue”};

[1596] interface bus_ts(unsigned 4 Input with {extlib=“plugin.dll”,

[1597] extinst=“some instance string”,

[1598] extfunc=“BusNameGetValue”})

[1599] BusName (unsigned 4 Output with {extlib=“plugin.dll”,

[1600] extinst=“some instance string”, extfunc=“BusNameSetValue”),

[1601] unsigned 1 Enable with {extlib=“plugin.dll”, extinst=”some

[1602] instance string”, extfunc=“BusNameEnable”});

[1603] Data Structures

[1604] Structures Passed on Startup

[1605] The following data structure passes essential information fromthe simulator to the plugin on startup.

[1606] HCPLUGIN_INFO

[1607] typedef struct

[1608] {

[1609] unsigned long Size;

[1610] void *State;

[1611] HCPLUGIN_CALLBACKS CallBacks;

[1612] } HCPLUGIN_INFO;

[1613] Members

[1614] Size Set to sizeof(HCPLUGIN_INFO) as a corruption check.

[1615] State Simulator identifier which may be used in callbacks fromthe plugin to the simulator. This value should be passed in future callsto any function in the CallBacks structure.

[1616] Call Backs Data structure containing pointers to the callbackfunctions from the plugin to the simulator. See below for details ofthese functions.

[1617] Callback Data Structure

[1618] HCPLUGIN_CALLBACKS

[1619] The pointers to the callback functions are contained in thefollowing structure, which is a member of the HCPLUGIN_INFO structurepassed to the PlugInOpen( ) function. Size should be set tosizeof(HCPLUGIN_CALLBACKS).

[1620] typeface struct

[1621] {

[1622] unsigned long Size;

[1623] HCPLUGIN_ERROR_FUNC PluginError;

[1624] HCPLUGIN_GET_VALUE_COUNT_FUNC PluginGetvaluecount;

[1625] HCPLUGIN_GET_VALUE_FUNC PluginGetValue;

[1626] HCPLUGIN_GET_MEMORY_ENTRY_FUNC PluginGetMemoryEntry;

[1627] } HCPLUGIN_CALLBACKS;

[1628] Source File Position Structures

[1629] A source position consists of a list of individual source coderanges. Each range details the source file and a range of lines andcolumns. The list of ranges consists of a singly linked list of sourcecode ranges. Lists of positions are generated by some Handel-C sourcecode constructs. For example, a call to a macro proc produces positionsfor the body elements of the macro proc with two members of the positionrange list. One points to inside the macro proc body and the otherpoints to the call of the macro proc. Lists of positions are alsogenerated for replicators and arrays of functions. The following datastructures are used to represent source positions of objects:

[1630] HCPLUGIN_POS_ITEM

[1631] typedef struct HCPLUGIN_POS_ITEM_tag

[1632] {

[1633] unsigned long Size;

[1634] char *FileName;

[1635] long StartLine;

[1636] long StartColumn;

[1637] long EndLine;

[1638] long EndColumn;

[1639] struct HCPLUGIN_POS_ITEM_tag *Next;

[1640] } HCPLUGIN_POS_ITEM;

[1641] Members

[1642] Size Set to sizeof(HCPLUGIN_POS_ITEM) as a corruption check.

[1643] FileName Source file name of position range.

[1644] StartLine First line of range. —1 indicates the filename is anobject file with no debug information. Line counts start from zero.

[1645] StartColumn First column of range. —1 indicates the filename isan object file with no debug information. Column counts start from zero.

[1646] EndLine Last line of range. —1 indicates the filename is anobject file with no debug information. Line counts start from zero.

[1647] EndColumn Last column of range. —1 indicates the filename is anobject file with no debug information. Column counts start from zero.

[1648] Next Pointer to next position range in list. NULL indicates thisis the last position range in the list.

[1649] HCPLUGIN_POSITION

[1650] typedef struct

[1651] {

[1652] unsigned long Size;

[1653] HCPLUGIN _POS_ITEM *SourcePos;

[1654] } HCPLUGIN_POSITION

[1655] Members

[1656] Size Set to sizeof(HCPLUGIN_POSITION) as a corruption check.

[1657] SourcePos Pointer to first position range in the linked list.

[1658] Variable Value Structures

[1659] The following data structure is used to pass information onvariable values from the simulator to the plugin. The plugin can queryand set the values of variables in the simulator using these datastructures and the associated callback functions of typesHCPLUGIN_GET_VALUE_FUNC and HCPLUGIN_GET_MEMORY_ENTRY_FUNC. Values areaccessed via an index using these functions. See below for furtherdetails of these functions.

[1660] HCPLUGIN _VALUE

[1661] typeface enum

[1662] {

[1663] HCPluginValue,

[1664] HCPluginArray,

[1665] HCPluginStruct,

[1666] HCPluginRAM,

[1667] HCPluginROM,

[1668] HCPluginWOM,

[1669] } HCPLUGIN_VALUE_TYPE;

[1670] The HCPLUGIN_VALUE_TYPE enumerated type is used to define thetype of object value contained in the HCPLUGIN_VALUE data structure. Thevalues have the following meanings:

[1671] HCPluginValue General value used for registers and signals.

[1672] Data.ValueData member of the HCPLUGIN_VALUE structure should beused.

[1673] HCPluginArray Array value. Data structure contains a list ofvalue indices in the Data member of the HCPLUGIN_VALUE structure.

[1674] HCPluginStruct Structure value. Data structure contains a linkedlist of values in the Data member of the HCPLUGIN_VALUE structure.

[1675] HCPluginRAM RAM memory value. Data structure contains the numberof entries in the memory in the Data.MemoryData member ofHCPLUGIN_VALUE.

[1676] HCPluginROM ROM memory value. Data structure contains the numberof entries in the memory in the Data.MemoryData member ofHCPLUGIN_VALUE.

[1677] HCPluginWOM WOM memory value. Data structure contains the numberof entries in the memory in the Data.MemoryData member of HCPLUGIN_VALUE

[1678] typedef struct HCPLUGIN_STRUCT_ENTRY_tag

[1679] {

[1680] unsigned long Size;

[1681] HCPLUGIN _POSITION *Position;

[1682] char *Name;

[1683] unsigned long ValueIndex;

[1684] struct HCPLUGIN_STRUCT_ENTRY tag *Next;

[1685] } HCPLUGIN STRUCT_ENTRY;

[1686] typedef struct HCPLUGIN_VALUE_tag

[1687] {

[1688] unsigned long Size;

[1689] HCPLUGIN_POSITION *Position;

[1690] unsigned long Internal[5];

[1691] int TopLevel;

[1692] char *Name;

[1693] HCPLUGIN_VALUE_TYPE Type;

[1694] union

[1695] {

[1696] struct

[1697] int Signed;

[1698] unsigned long Base;

[1699] unsigned long Width;

[1700] void *Value;

[1701] } ValueData;

[1702] struct

[1703] }

[1704] unsigned long *Elements;

[1705] unsigned long Length;

[1706] } ArrayData;

[1707] HCPLUGIN_STRUCT_ENTRY *StructData;

[1708] struct

[1709] {

[1710] unsigned long Length;

[1711] } MemoryData;

[1712] } Data;

[1713] } HCPLUGIN_VALUE;

[1714] of HCPLUGIN_VALUE Structure:

[1715] Size Set to sizeof(HCPLUGIN_VALUE) as a corruption check.

[1716] Position Source position of declaration of object.

[1717] Internal Internal data used by the debugger. Do not modify.

[1718] TopLevel Set to 1 if it's a top-level object or 0 otherwise.Examples of objects that are not top level are elements of arrays ormembers of structures. Used by the debugger.

[1719] Name Identifier of the object.

[1720] Type Type of object that this value represents. See above fordetails of the HCPLUGIN_VALUE_TYPE enumerated type.

[1721] Data Union containing the value data consisting ofData.ValueData, Data.ArrayData.

[1722] and Data.MemoryData.

[1723] Elements of HCPLUGIN_VALUE.Data

[1724] Data is used to represent basic values (e.g. registers andsignals) and contains the following members:

[1725] Signed Zero for an unsigned value, non-zero for a signed value.

[1726] Base Default base used to represent this value (specified usingthe base spec in the source code). Can be 2, 8, 10 or 16 or 0 for none.

[1727] Width Width of value in bits.

[1728] Value Pointer to value. If Width is less than or equal to 32 bitsthen this is a long * or unsigned long *. If Width is less than or equalto 64 bits then this is a _int64 * or unsigned _int64 *. If Width isgreater than 64 bits then this is a NUMLIB_NUMBER ** Data stored inlong, unsigned long, _int64 and unsigned _int64 types is left aligned.This means it occupies the most significant bits in the word and not theleast significant bits. For example, 3 stored in a 3 bit wide number ina 32-bit word is represented as 0x60000000. Functions usingNUMLIB_NUMBER structures are sescribed hereinafter.

[1729] DataArrayData is used to represent array values and contains thefollowing members:

[1730] Elements Array of value indices of members of array. Theseindices can be passed to further calls to the get value function.

[1731] Length Number of elements in the array.

[1732] Data.StructData is used to represent structure values and pointsto the head of a NULL terminated linked list of structure memberobjects. See below for details of the HCPLUGIN STRUCT_ENTRY structure.

[1733] Data.MemoryData is used to represent memory (RAM, ROM and WOM)values and contains the following members:

[1734] Length Number of elements in the memory.

[1735] Associated Functions

[1736] Use the callback function HCPLUGIN_GET_MEMORY_ENTRY_FUNC toaccess memory elements.

[1737] Simulator to Plugin Functions

[1738] These functions are called by the simulator to send informationto the plugin. They are called when simulation begins and ends, and atpoints in the simulator clock cycle. The plugin may act upon the call ordo nothing. The plugin may implement the function with identical nameand parameters.

[1739] void PlugInOpen(HCPLUGIN_INFO *Info, unsigned long NumInst)

[1740] The simulator calls this function the first time that the plugin.dll is used in a Handel-C session. Each simulator used may make onecall to this function for each plugin specified in the source code.

[1741] Info Pointer to structure containing simulator call backinformation.

[1742] NumInst Number of instances of the plugin specified in the sourcecode. One call to PluginOpenInstance( ) may be made for each of theseinstances.

[1743] PlugInOpenInstance

[1744] void *PlugInOpenInstance(char *Name, unsigned long NumPorts)

[1745] This function is called each time one starts a simulation. It iscalled once for each instance of the plugin the Handel-C source code. Aninstance is considered unique if a unique string is used in the extinstspecification. The plugin should return a value used to identify theinstance in future calls from the simulator. This value may be passed tofuture calls to

[1746] PlugInOpenPort( ). PlugInSet( ), PlugInGet( ), PlugInStartCycle(),

[1747] PlugInEndCycle( ) and PlugInCloseInstance( ).

[1748] Name String specified in the extinst specification in the sourcecode.

[1749] NumPorts Number of ports associated with this instance. One callto PluginOpenPort( ) may be made for each of these ports.

[1750] PlugInOpenPort

[1751] void*PlugInOpenPort(void *Instance, char *Name, int Direction,unsigned long Bits)

[1752] This function is called each time one starts a simulation. It iscalled once for each interface port associated with this plugin in thesource code. The plugin should return a value used to identify the portin future calls from the simulator. This value may be passed to futurecalls to

[1753] lugInGet( ),

[1754] PlugInSet( ), and PlugInClosePort( ).

[1755] Instance Value returned by the PlugInOpenInstance( ) function.

[1756] Name Name of the port from the interface definition in the sourcecode.

[1757] Direction Zero for a port transferring data from plugin tosimulator, non-zero for a port transferring data from simulator toplugin.

[1758] Bits Width of port.

[1759] PlugInSet

[1760] void PlugInSet(void *Instance, void *Port, unsigned long Bits,void *Value)

[1761] This function is called by the simulator to pass data fromsimulator to plugin. It is guaranteed to be called every time the valueon the port changes but may be called more often than that.

[1762] Instance Value returned by the PlugInOpenInstance( ) function.

[1763] Port Value returned by the PluginOpenPort( ) function.

[1764] Bits Width of port.

[1765] Value Pointer to value. If Bits is less than or equal to 32 bitsthen this is a long * or unsigned long *. If Bits is less than or equalto 64 bits then this is an int64 * or unsigned int64 *. If Bits isgreater than 64 bits then this is a NUMLIB_NUMBER **. Data stored inlong, unsigned long, unsigned long, _int64 and unsigned _int64 types isleft aligned. This means it occupies the most significant bits in theword and not the least significant bits. For example 3 stored as a 3 bitwide number in a 32-bit word is represented as 0x60000000. Functionsusing NUMILIB_NUMBER structures are described hereinafter.

[1766] Where 32 bit or 64 bit widths are used, data is stored in themost significant bits.

[1767] PlugInGet

[1768] void PlugInGet(void *Instance, void *Port, unsigned long Bits,void *Value)

[1769] This function is called by the simulator to get data from theplugin. One may use any name he or she wishes for this function(specified in by extfunc) but the parameters may remain the same.

[1770] Instance Value returned by the PlugInOpenInstance( ) function.

[1771] Port Value returned by the PlugInOpenPort( ) function.

[1772] Bits Width of port.

[1773] Value Pointer to value. If Bits is less than or equal to 32 bitsthen this is a long * or unsigned long *. If Bits is less than or equalto 64 bits then this is a_int64 (Microsoft specific type) * or unsigned_int64 *. If Bits is greater than 64 bits then this is a NUMLIB_NUMBER**. Data stored in long, unsigned long, _int64 and unsigned _int64 typesis left aligned. This means is occupies the most significant bits in theword and not the least significant bits. For example, 3 stored in a 3bit wide number in a 32-bit word is represented as 0x60000000. Functionsusing NUMLIB_NUMBER structures are described hereinafter.

[1774] Where 32 bit or 64 bit widths are used, data may be stored in themost significant bits. One may left-shift the number into the MSBs so itmay be read correctly by the Handel-C code.

[1775] PlugInStartCycle

[1776] void PlugInStartCycle(void *Instance)

[1777] This function is called by the simulator at the start of everysimulation cycle.

[1778] Instance Value returned by the PlugInOpenInstance( ) function.

[1779] PlugInMiddleCycle

[1780] void PlugInMiddleCycle(void *Instance)

[1781] This function is called by the simulator immediately before anyvariables within the simulator are updated.

[1782] Instance Value returned by the PlugInOpenInstance( ) function.

[1783] PlugInEndCycle

[1784] void PlugInEndCycle(void *Instance)

[1785] This function is called by the simulator at the end of everysimulation cycle.

[1786] Instance Value returned by the PlugInOpenInstance( ) function.

[1787] PlugInClosePort

[1788] void PlugInClosePort(void *Port)

[1789] The simulator calls this function when the simulator is shutdown. It is called once for every call made to PlugInOpenPort( ).

[1790] Port Value returned by the PlugInOpenPort( ) function.

[1791] PlugInCloseInstance

[1792] void PlugInCloseInstance(void *Instance)

[1793] The simulator calls this function when the simulator is shutdown. It is called once for every call made to PlugInOpenInstance( ).

[1794] Instance Value returned by the PlugInOpenInstance( ) function.

[1795] PlugInClose

[1796] void PlugInClose(void)

[1797] The simulator calls this function when the simulator is shutdown. It is called once for every call made to PlugInOpen( ).

[1798] Simulator Callback Functions

[1799] The simulator callback functions are used by plugins to query thestate of variables within the Handel-C program. This can be used tomodel memory mapped registers or shared memory resources or to displaydebug values in non-standard representations (e.g. oscilloscope andlogic analyzer displays). The plugin receives pointers to thesefunctions in the Info parameter of the PlugInOpen( ) function call madeby the simulator at startup.

[1800] HCPLUGIN_ERROR_FUNC

[1801] typedef void (*HCPLUGIN_ERROR_FUNC)(void *State, unsigned longLevel,char *Message);

[1802] The plugin should call this function to report information,warnings or errors. These messages may be displayed in the GUI debugwindow. In addition, an error may stop the simulation. State Statemember from the HCPLUGIN_INFO structure passed to the PlugInOpen( )function.

[1803] Level 0 Information

[1804] 1 Warning

[1805] 2 Error.

[1806] Message Error message string.

[1807] HCPLUGIN_GET_VALUE_COUNT_FUNC

[1808] typedef unsigned long (*HCPLUGIN_GET_VALUE_COUNT_FUNC) (void*State);

[1809] The plugin should call this function to query the number ofvalues in the simulator. This number provides the maximum index for theHCPLUGIN_GET VALUE_FUNC function.

[1810] State State member from the HCPLUGIN_INFO structure passed to thePlugInOpen( ) function.

[1811] HCPLUGIN_GET_VALUE_FUNC

[1812] typedef void (*HCPLUGIN_GET_VALUE_FUNC)(void *State, unsignedlong Index, HCPLUGIN _VALUE *Value);

[1813] The plugin should call this function to get a variable value fromthe simulator. State State member from the HCPLUGIN_INFO structurepassed to the PlugInOpen( ) function. Index of the variable. Should bebetween 0 and the one less than the return value of the HCPLUGIN GETVALUE COUNT FUNC function inclusive.

[1814] A map of index to variable name can be built up at startup byrepeatedly calling this function and examining the Value structurereturned.

[1815] Value Structure containing information about the value.

[1816] HCPLUGIN_GET_MEMORY_ENTRY_FUNC

[1817] typedef void (*HCPLUGIN_GET_MEMORY_ENTRY_FUNC) (void *State,unsigned long Index, unsigned long Offset, HCPLUGIN_VALUE *Value);

[1818] The plugin should call this function to get a memory entry fromthe simulator.

[1819] State State member from the HCPLUGIN_INFO structure passed to thePlugInOpen( ) function.

[1820] Index Index of the variable. Should be between 0 and one lessthan the return value of the HCPLUGIN_GET_VALUE_COUNT_FUNC functioninclusive. A map of index to variable name can be built up at startup byrepeatedly calling this function and examining the Value structurereturned.

[1821] Offset Offset into the RAM. For example, to obtain the value ofx[43], Index should refer to x and this value should be 43.

[1822] Value Structure containing information about the value.

[1823] Example

[1824] This example consists of three files:

[1825] A Handel-C file which invokes the plugin through interfaces

[1826] ANSI-C file containing the plugin functions

[1827] An ANSI-C header file defining the plugin structures

[1828] Plugin file: plugin-Demo.c

[1829] This simple example has one function (MyBusOut) that reads avalue from a simulator interface and one function (MyBusIn) that doublesa value and writes it to a simulator interface.

[1830] It responds to the calls to PlugInOpenInstance( ) andPlugInOpenPort( ) by returning NULL. All the other required pluginfunctions have been defined but do nothing.

[1831] #include “plugin.h”

[1832] #define dll _(—)_declspec(dllexport)

[1833] dll void PlugInOpen(HCPLUGIN_INFO *Info, unsigned long NumInst)

[1834] {

[1835] //this function intentionally left blank

[1836] //intialisating before the first simulation is run

[1837] }

[1838] dll void PlugInClose(void)

[1839] {

[1840] //tidy-up after final simulation

[1841] }

[1842] dll void *PlugInOpenInstance(char *Name,unsigned long NumPorts)

[1843] {

[1844] //invoked when one starts a simulation

[1845] //initialize anything required for this simulation

[1846] return NULL;

[1847] }

[1848] dll void PlugInCloseInstance(void *Instance)

[1849] {

[1850] }

[1851] dll void *PlugInOpenPort(void *Instance, char *Name, int

[1852] Direction unsigned long Bits)

[1853] {

[1854] //an opportunity to initialize any data structures associated

[1855] with

[1856] //this port and return the pointer associated with it (which

[1857] could

[1858] //then be passed to PlugInSet, etc.)

[1859] return NULL;

[1860] }

[1861] dll void PlugInClosePort(void *Port)

[1862] {

[1863] }

[1864] static unsigned long DataIn;

[1865] dll void MyBusOut(void *Instance, void *Port, unsigned long Bits,

[1866] void *Value)

[1867] {

[1868] DataIn <=*(long *)Value;

[1869] }

[1870] dll void MyBusIn(void *Instance, void *Port, unsigned long Bits,

[1871] void *Value)

[1872] {

[1873] *(long *)Value <=DataIn*2;

[1874] }

[1875] dll void PlugInStartCycle(void *Instance)

[1876] {

[1877] //call after start of clock cycle

[1878] //possible useful with non-standard clocks

[1879] }

[1880] dll void PlugInMiddleCycle(void *Instance)

[1881] {

[1882] }

[1883] dll void PlugInEndCycle(void *Instance)

[1884] {

[1885] }

[1886] C header file: plugin.h

[1887] This is provided on the installation CD. It contains declarationsof the required structures.

[1888] Handel-C file: plugin-demo.c

[1889] setclock <=internal “1”;

[1890] int 8 a,b;

[1891] macro expr MyOutExpr <=a;

[1892] interface bus_out( ) MyBusOut(MyOutExpr) with

[1893] {extlib=“pluginDemo.dll”, extinst=“0”, extfunc=“MyBusOut”};

[1894] interface bus_in(int 8) MyBusIn( ) with

[1895] {extlib=“pluginDemo.dll”, extinst=“0”, extfunc=“MyBusIn”)};

[1896] void main(void) {

[1897] (a=1; a<10; a++) {

[1898] b<=MyBusIn.in;

[1899] }

[1900] Numlib Library

[1901] The numlib.dll library is provided. This contains a series ofroutines to deal with values that are greater than 64 bits wide. Thesenumbers are stored in a NUMLIB_NUMBER structure and these routines usethis structure to operate on. There are routines to convertNUMLIB_NUMBER structures to 32 and 64-bit values.

[1902] These routines can be accessed by including the header filenumlib.h. Their functions are: Number allocation and de-allocationEXPORT void NumLibNew(NUMLIB_NUMBER **Num, unsigned long Width) GrabWidth space for value indirectly pointed to by Num. Provide pointer tospace acquired in Num.

[1903] For example:

[1904] NUMLIB_NUMBER *Fred;

[1905] NumLibNew(&Fred, 453);

[1906] EXPORT void NumLibFree(NUMLIB_NUMBER *Num) Free grabbed space forvalue pointed to by Num.

[1907] For example: NumLibFree(Fred);

[1908] General Number Handling Routines

[1909] EXPORT void NumLibSet(char *a, NUMLIB_NUMBER *Result) Set valuepointed to by Result to the value of string a.

[1910] For example:

[1911]  NUMLIB_NUMBER *Fred;

[1912] NumLibNew(&Fred, 453);

[1913] NumLibSet(“1245216474847832194873205083294”, Fred);

[1914] EXPORT void NumLibCopy(NUMLIB_NUMBER *Source, NUMLIB_NUMBER*Result) Copy value pointed to by Source to value pointed to by Result.

[1915] EXPORT void NumLibPrint(unsigned long Base, int Signed,NUMLIB_NUMBER *Source)Print value pointed to by Source to screen in Base(display as signed or unsigned according to Signed). If Signed isnon-zero, number is treated as signed (e.g. “—1”). If Signed is zero,numbers may be treated as unsigned (e.g. “255”)

[1916] EXPORT void NumLibPrintFile(FILE *FilePtr, unsigned long Base,int Signed, NUMLIB_NUMBER *Source) Write value pointed to by Source tofile pointed to by FilePtr as above.

[1917] EXPORT unsigned long NunLibPrintString(char *Buffer, unsignedlong BufferLength, unsigned long Base, int Signed, NUMLIB_NUMBER*SourceIn). Write value pointed to by SourceIn as string to Buffer ingiven Base (length of Buffer given in Bufferlength). BufferLength is themaximum length that may be written.

[1918] EXPORT uint32 NumLibBits(NUMLIB_NUMBER *a) Calculate the width ofvalue pointed to by a and return number of bits (i.e. return the widthof a specified in NumLibNew).

[1919] EXPORT void NumLibSetBit(NUMLIB_NUMBER *a, uint32 Bit, int Value)Set bit Bit of value pointed to by a to Value (0 or 1).

[1920] EXPORT int NumLibGetBit(NUMLIB_NUMBER *a, uint32 Bit) Get valueof bit Bit of value pointed to by a.

[1921] EXPORT int32 NumLibGetLong(NUMLIB_NUMBER *a) Convert valuepointed to by a to 32 bits and return it. The least significant bits areused and the result is right aligned (i.e. normal numbers not pluginstyle numbers).

[1922] EXPORT int64 NumLibGetLongLong(NUMLIB_NUMBER *a) Convert valuepointed to by a to 64 bits and return it. The least significant bits areused and the result is right aligned (i.e. normal numbers not pluginstyle numbers).

[1923] EXPORT void NumLibWriteFile(NUMLIB_NUMBER *a, FILE *FilePtr)Write value pointed to by a in binary format to file pointed to byFilePtr.

[1924] EXPORT void NumLibReadFile(NUMLIB_NUMBER *a, FILE *FilePtr) Readbinary format number from a file pointed to by FilePtr and put theresult in a. This is the reverse of NumLibWriteFile. The width of a maybe correct.

[1925] E.g.

[1926] NUMLIB_NUMBER *Fred;

[1927] FILE *FilePointer=fopen(“file.dat”, “rb”); NumLibNew(&Fred, 453);

[1928] NumLibReadFile(Fred, FilePointer);

[1929] Arithmetic operations

[1930] Note that in Handel-C, one can only do signed by signed orunsigned by unsigned division and cannot mix types. All operations areHandel-C like, and require some widths and/or type information.

[1931] EXPORT void NumLibUMinus(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b);b=-a

[1932] EXPORT void NumLibAdd(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,NUMLIB_NUMBER *Result) Result=a+b

[1933] EXPORT void NunLibSubtract(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,NUMLIB_NUMBER *Result) Result=a−b

[1934] EXPORT void NumLibMultiply(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,NUMLIB_NUMBER *Result) Result=a*b

[1935] EXPORT void NumLibDivide(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b, intSigned, NUMLIB_NUMBER *Result) Result=a/b. All numbers treated as signedor unsigned, depending on the value of Signed.

[1936] EXPORT void NumLibMod(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b, intSigned, NUMLIB_NUMBER *Result) Result=a % b. All numbers treated assigned or unsigned, depending on the value of Signed.

[1937] EXPORT void NumLibDivMod(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b, intSigned, NUMLIB_NUMBER *DivResult, NUMLIB_NUMBER *ModResult)DivResult=a/b, ModResult=a % b. All numbers treated as signed orunsigned, depending on the value of Signed.

[1938] Comparisons

[1939] EXPORT unsigned long NumLibCompareEq(NUMLIB_NUMBER *a, char *b)Return result of comparison of number a to string b Equivalent to:

[1940] NUMLIB_NUMBER *Temp;

[1941] unsigned long Res;

[1942] NumLibNew(&Temp, a->Width);

[1943] NumLibSet(b, Temp);

[1944] NumLibEquals(a, Temp, &Res);

[1945] NumLibFree (Temp);

[1946] return Res;

[1947] EXPORT void NumLibEquals(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result) Return result of (a=b)

[1948] EXPORT void NumLibNotEquals(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result); Return result of (a !=b)

[1949] EXPORT void NumLibSGT(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result); Return result of (a>b) (a and b signed)

[1950] EXPORT void NumLibSGTE(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result) Return result of (a>=b) (a and b signed)

[1951] EXPORT void NumLibSLT(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result) Return result of (a<b) (a and b signed)

[1952] EXPORT void NumLibSLTE(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result) Return result of (a<=b) (a and b signed)

[1953] EXPORT void NumLibUGT(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result) Return result of (a>b) (a and b unsigned)

[1954] EXPORT void NumLibUGTE(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned *Result) Return result of (a>=b) (a and b unsigned)

[1955] EXPORT void NumLibULT(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result) Return result of (a<b) (a and b unsigned)

[1956] EXPORT void NumLibULTE(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,unsigned long *Result) Return result of (a<=b) (a and b unsigned)

[1957] EXPORT void NumLibCond(unsigned long *Condition, NUMLIB_NUMBER*a, UMLIB_NUMBER *b, NUMLIB_NUMBER *Result); Return result of Condition? a : b.

[1958] Equivalent to:

[1959] if (*Condition==0)

[1960] {

[1961] NumLibCopy (b, Result);

[1962] }

[1963] else

[1964] {

[1965] NumLibcopy (a, Result);

[1966] }

[1967] Bitwise operations

[1968] EXPORT void NumLibNot(NUMLIB_NUMBER *a, NUMLIB_NUMBER *Result)Value pointed to by Result=˜a

[1969] EXPORT void NumLibAnd(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,NUMLIB_NUMBER *Result) Value pointed to by Result=a & b

[1970] EXPORT void NumLibOr(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,NUMLIB_NUMBER *Result) Value pointed to by Result=a | b

[1971] EXPORT void NumLibXor(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,NUMLIB_NUMBER *Result) Value pointed to by Result a^ b

[1972] Concatenation Operations

[1973] In all the functions the int32 and int64 values are left alignedin line with the plugin interface.

[1974] EXPORT void NumLibCat64_(—)32(uint64 *a, unsigned long wa,unsigned long *b, unsigned long wb, NUMLIB_NUMBER *Result) Concatenatewa bits of 64 bit a and wb bits of 32 bit b and place it in valuepointed to by Result. Value pointed to by Result=int wa a @ int wb b

[1975] EXPORT void NumLibCat32_(—)64(unsigned long *a, unsigned longwa,uint64 *b, unsigned long wb, NUMLIB_NUMBER *Result) Concatenate wabits of 32 bit a and wb bits of 64 bit b and place it in value pointedto by Result. Value pointed to by Result=int wa a @ int wb b

[1976] EXPORT void NumLibCat64_(—)64(uint64 *a, unsigned long wa, uint64*b, unsigned long wb, NUMLIB_NUMBER *Result) Concatenate wa bits of 64bit a and wb bits of 64 bit b and place it in value pointed to byResult. Value pointed to by Result=int wa a @ int wb b

[1977] EXPORT void NumLibCat32_n(unsigned long *a, unsigned long wa,NUMLIB_NUMBER *b, NUMLIB_NUMBER *Result) Concatenate wa bits of 32 bit awith value b and place it in value pointed to by Result. Value pointedto by Result=int wa a @ b

[1978] EXPORT void NumLibCatn_(—)32(NUMLIB_NUMBER *a, unsigned long *b,unsigned long wb, NUMLIB_NUMBER *Result)Concatenate value a with wb bitsof 32 bit b and place it in value pointed to by Result. Value pointed toby Result=a @ int wb b

[1979] EXPORT void NumLibCat64_n(uint64 *a, unsigned long wa,NUMLIB_NUMBER *b, NUMLIB_NUMBER *Result) Concatenate wa bits of 64 bit awith value b and place it in value pointed to by Result. Value pointedto by Result=int wa a @ b.

[1980] EXPORT void NumLibCatn_(—)64(NUMLIB_NUMBER *a, uint64 *b,unsigned long wb, NUMLIB_NUMBER *Result) Concatenate value a with wbbits of 64 bit b and place it in value pointed to by Result. Valuepointed to by Result=a @ int wb b

[1981] EXPORT void NunLibCat(NUMLIB_NUMBER *a, NUMLIB_NUMBER *b,NUMLIB_NUMBER *Result); Concatenate value a with value b and place it invalue pointed to by Result. Value pointed to by Result=a @ b

[1982] Drop Operations

[1983] EXPORT void NumLibDrop32(NUMLIB_NUMBER *a, unsigned long b,unsigned long * Result) Drop b bits from a and place it in 32-bitResult. Value pointed to by Result=a\\b

[1984] EXPORT void NumLibDrop64(NUMLIB_NUMBER *a, unsigned long b,uint64 *Result) Drop b bits from a and place it in 64-bit Result. Valuepointed to by Result=a \\b

[1985] EXPORT void NumLibDrop(NUMLIB_NUMBER *a, unsigned long b,NUMLIB_NUMBER * Result) Drop b bits from a and place it in Result.Valuepointed to by Result=a \\b

[1986] Take Operations

[1987] EXPORT void NumLibTake32(NUMLIB_NUMBER *a, unsigned long b,unsigned long *Result) Take b bits from a and place it in 32-bit Result.Value pointed to by Result=a <- b

[1988] EXPORT void NumLibTake64(NUMLIB_NUMBER *a, unsigned long b,uint64 *Result) Take b bits from a and place it in 64-bit Result. Valuepointed to by Result=a <- b

[1989] EXPORT void NumLibTake(NUMLIB NUMBER *a, unsigned long b,NUMLIB_NUMBER *Result) Take b bits from a and place it in Result. Valuepointed to by Result=a <- b

[1990] Shift Operations

[1991] EXPORT void NumLibLSL(NUMLIB NUMBER *a, unsigned long b,NUMLIB_NUMBER *Result) Result=a<<b

[1992] EXPORT void NumLibLSR(NUMLIB_NUMBER *a, unsigned long b,NUMLIB_NUMBER *Result) Result=a>>b. Logical right-shift: the top bitsare zero-padded.

[1993] EXPORT void NumLibASR(NUMLIB_NUMBER *a, unsigned long b,NUMLIB_NUMBER *Result) Result=a >>b Arithmetic right-shift: the top bitsare sign-extended.

[1994] Bit Selection Operations

[1995] EXPORT void NumLibBitRange32(NUMLIB_NUMBER *a, unsigned long b,unsigned long c, unsigned long *Result) 32 bit value pointed to byResult=a [b−1 : c]

[1996] EXPORT void NumLibBitRange64(NUMLIB_NUMBER *a, unsigned long b,unsigned long c, uint64 *Result) 64 bit value pointed to by Result=a[b−1: c]

[1997] EXPORT void NumLibBitRange(NUMLIB_NUMBER *a, unsigned long b,unsigned long c, NUMLIB_NUMBER *Result).Result=a [b−1: c]

[1998] Bit Insertion Operations

[1999] EXPORT void NumLibInsert32(unsigned long *a, unsigned long wa,unsigned long s, NUMLIB_NUMBER *Result) Insert bits of a into Resultwith LSB at position s. Width a is wa and a is <=32 bits wide.

[2000] EXPORT void NumLibInsert64(uint64 *a, unsigned long wa, unsignedlong s, NUMLIB_NUMBER *Result) Insert bits of a into Result with LSB atposition s. Width a is wa and a is <=64 bits wide.

[2001] EXPORT void NumLibInsert(NUMLIB_NUMBER *a, unsigned long s,NUMLIB_NUMBER *Result) Insert bits of a into Result with LSB at positions.

[2002] Plugin Supplied

[2003] The following plugins are supplied to assist in simulatingHandel-C programs. sharer.dll allows a port to be used by more than oneplugin.

[2004] synchroniser.dll synchronizes Handel-C simulations so that theyrun at the correct rate relative to one another.

[2005] connector.dll connects simulation ports together so that data canbe exchanged between simulations.

[2006] 7_segment.dll simulate a 7-segment display.

Sharing a Port Between Plugins: sharer.dll

[2007] One can share a port between two or more plugins. One can shareoutput ports to distribute the same data to multiple plugins. Inputports can be shared so that more than one plugin can feed data into theprogram (for example, to simulate tri-state ports). If more than oneplugin provides data to the same port on the same clock cycle, the lastpiece of data fetched is the one used.

[2008] Syntax

[2009] To share a port, the with specification of the port or interfacemay contain:

[2010] extlib=“sharer.dll”

[2011] extfunc=“SharerGetSet”

[2012] extinst=“ShareRecords”

[2013] The ShareRecords string consists of a Share record for everyplugin which a port needs to be connected to. Share records have thefollowing syntax: Share={extlib=<lib-name>, extinst=<extinst-string>,extfunc=<func-name>} The items within angle brackets have the samemeaning as they have when they occur as the extlib, extinst and extfuncfields. FIG. 43 illustrates a plurality of possible values and meanings4300 associated with libraries of the present invention.

[2014] interface bus_out( ) seg7_output(encode_out)

[2015] with {extlib=“sharer.dll”,

[2016] extinst=“\

[2017] Share={extlib=<7segment.dll>,

[2018] extinst=<A>,

[2019] extfunc=<PlugInSet>}\

[2020] Share={extlib=<connector.dll>,

[2021] extinst=<SS (7)>, \

[2022] extfunc=<ConnectorGetSet>}

[2023] ”,

[2024] extfunc=“SharerGetSet”

[2025] {;

[2026] Synchronizing Multiple Simulations: synchroniser.dll

[2027] If one wants to simulate multiple programs with different clockperiods, one can use the synchroniser.dll. One then informs thesynchronizer of their relative clock rates. The synchronizer may suspendsimulations until they can complete a cycle in step with othersimulations.

[2028] If one is single-stepping several synchronized simulations, somemay be suspended until he or she has stepped other simulations to apoint where the cycles coincide. There may always be at least onesimulation that can be stepped.

[2029] To complete a simulation that is synchronized with other pausedsimulations (i.e. in break mode), one may have to single step the pausedsimulations until the finishing simulation can complete.

[2030] Syntax

[2031] To invoke synchroniser.dll, one may use the following withspecifications in the set clock statement:

[2032] extlib=“synchroniser.dll”

[2033] extfunc=“SynchroniserGetSet”

[2034] extinst=“clockPeriod”

[2035] The clockPeriod string may contain a positive integer thatrepresents the period of the clock. This is assumed to be in the sametime units for all simulations that are to be synchronized.

[2036] set clock=external “P1” with

[2037] {extlib=“synchroniser.dll”,extinst=“100”,

[2038] extfunc=SynchroniserGetSet”};

[2039] Connecting Simulations Together: connector.dll

[2040] The connector allows one to connect two simulations together.

[2041] Syntax

[2042] One may connect a simulation to connector.dll by specifying thefollowing in the with specification for a port.

[2043] extlib=“connector.dll”,

[2044] extinst=“terminalName (width) [[bitRange]]”,

[2045] extfunc=¢ConnectorGetSet”

[2046] Where:

[2047] terminalName is the name of the virtual terminal that the port isconnected to. It may be any Handel-C identifier. All ports connected toterminalName are connected together. The terminal may be created if itdoes not exist.

[2048] width is the width of the terminal in bits. This may be the samefor every occurrence of the same terminal name.

[2049] [bitRange] is optional. It specifies which bits of the port areconnected to which bits of the terminal. If used, bitRange may specifythe connections for all bits within the port.

[2050] Port bits are defined by their position within bitRange; terminalbits are specified by value. The first (leftmost) value in bitRangerepresents the most significant port bit, and the last (rightmost) valuethe least significant port bit. Terminal bits can be specified as aninclusive range [n:n], or a number. To leave a port bit unconnected,specify X as its terminal bit value.

[2051] If bitRange is omitted, bit 0 of the port may be connected to bit0 of the terminal, bit 1 to bit 1 etc. The stringextinst=“connect1(16)[13,14,X,X,11:8]” connects an 8-bit port to a16-bit terminal connect1 with the cross-connections below in Table 1.TABLE 1 Port bits Terminal bits 0 8 1 9 2 10 3 11 4 X 5 X 6 14 7 13

[2052] // Program A interface

[2053] interface bus_out( ) seg7_output(encode_out)

[2054] with {extlib=“connector.dll”,

[2055] extinst=“SS(7)”, extfunc=“ConnectorGetSet”};

[2056] // Program B interface

[2057] interface bus_in(unsigned 7 in) seg7_input( )

[2058] with {extlib=“connector.dll”,

[2059] extinst=“SS(7)”, extfunc=“ConnectorGetSet”};

[2060] Simulating a 7-segment Display 7segment.dll

[2061] The 7 segment display allows one to connect a simulation of aseven segment display to a 7-bit wide output port.

[2062] Syntax

[2063] One may connect to 7segment.dll by specifying the following inthe with specification for the 7-bit wide output port:

[2064] extlib=“7segment.dll”

[2065] extinst=“windowName”

[2066] extfunc=“PlugInSet”

[2067] when the Handel-C program is simulated, a window containing asingle 7-segment display appears. The window has the title windowName.The program may invoke any number of 7-segment display windows. Thesegments correspond to the following bits (where bit (0) is the leastsignificant bit). A bit value of 0 turns the segment on, 1 turns it offThe following array encodes the digits 0 to 9 to drive the 7segment.dll.

unsigned 7 encoder[10]={0x1, 0x4f, 0x12, 0x06, 0x4c, 0x24, 0x20, 0x0f,0x00, 0x04{;.

[2068] Example

[2069] this example consists of two separate Handel-C projects: ProjectA and Project B.

[2070] Project A:

[2071] Increments a modulo-10 counter every cycle and outputs the valueof the counter to the 7segment.dll plugin.

[2072] Outputs the value of the counter to the terminal called SS(7)every cycle.

[2073] Project A's cycles are 100 time units long.

[2074] Project B:

[2075] Increments a modulo-10 counter on alternate cycles and outputsthe value of the counter to the 7segment.dll plugin.

[2076] Alternate cycles, reads the value from the terminal called SS(7)and outputs it to the 7segment.dll plugin.

[2077] Project B's cycles are 50 time units long.

[2078] Project B may be stepped twice for every step of project A.

[2079]FIG. 44 shows how the synchronization 4400 works whensingle-stepping the two projects in simulation.

[2080] At point 1 both simulations are ready to step. If one stepsProject B first, it may suspend at point 2, as it cannot continue untilA has caught up. A may be stepped. It may suspend before 4, as it waitsfor B to catch up. Meanwhile, B can complete its first step to reach 3.One can then step B, so that it can catch up with A, and both projectsare ready to step. If one steps Project A first, it suspends as it maywait for B to reach 4 before it can continue. Now he or she may stepProject B. When B is stepped, it reaches 3. A may still wait. When B isstepped again, it catches A, and both A and B are ready to continue.

[2081] If one single step the example above, two 7 segment displaywindows appear.

[2082] Once both simulations have passed the initialization part andentered the main loop, the windows should display these numbers.

[2083] Time units 0 50 100 150 200 250 200 250 300 350

[2084] A window 0 0 0 1 1 2 2 3 3 4 . . .

[2085] B window 0 1 0 2 1 3 2 4 3 5 . . .

[2086] Source file for Project A:

[2087] set clock=external “P1” with

[2088] {extlib=“synchroniser.dll”,extinst=“100”,

[2089] extfunc=“SynchroniserGetSet”};

[2090] signal unsigned 7 encode_out;

[2091] interface bus_out( ) seg7_output(unsigned 7 output=encode_out)

[2092] with {extlib=“sharer.dll”,

[2093] extinst“\

[2094] Share={extlib=<7segment.dll>,

[2095] extinst=<A>,

[2096] extfunc=<PlugInSet>}\

[2097] Share={extlib=<connector.dll>,

[2098] extinst=<SS(7)>, \

[2099] extfunc=<ConnectorGetSet>}

[2100] “,extfunc=“SharerGetSet”

[2101] };

[2102] //define values to light 7-segment display from 0-9

[2103] rom encoder[10]=

[2104] {0x01, 0x4f,0x12, 0x06, 0x4c, 0x24, 0x20, 0x0f, 0x00, 0x04};

[2105] void main(void)

[2106] {

[2107] unsigned 4 count;

[2108] count=0;

[2109] while(1)

[2110] par

[2111] {

[2112] count=(count==9) ? 0 : (count+1);

[2113] encode_out=encoder[count];

[2114] }

[2115] }

[2116] Source file for Project B:

[2117] set clock=external “P1” with {extlib=“synchroniser.dll”,

[2118] extinst=“50”, extfunc=“SynchroniserGetSet”};

[2119] signal unsigned 7 encode_out;

[2120] interface bus_out( ) seg7_output(unsigned 7 output=encode_out)

[2121] with {extlib=“7segment.dll”,

[2122] extinst=“B”,

[2123] extfunc=“PlugInSet”};

[2124] interface bus_in(unsigned 7 in) seg7_input( )

[2125] with {extlib=“connector.dll”,

[2126] extinst=“SS(7)”,

[2127] extfunc=“ConnectorGetSet”)};

[2128] //Define values to light 7-segment display from 0-9

[2129] rom encoder[10]=

[2130] {0x01, 0x4f, 0x12, 0x06, 0x4c, 0x24, 0x20, 0x0f, 0x00, 0x04};

[2131] void main(void)

[2132] {

[2133] unsigned 4 count;

[2134] count=0;

[2135] while(1)

[2136] {

[2137] par

[2138] {

[2139] count=(count==9) ? 0 : (count+1);

[2140] encode_out=encoder[count];

[2141] }

[2142] encode_out=seg7_input.in;

[2143] More information regarding cosimulation will now be set forth.

[2144] WP26 Cosimulation Tool

[2145] The present section proposes a number of interfaces to be used toenable multiple simulators to be used together in a generic fashion.First of all the objectives of the present embodiment are explained.

[2146] Objectives

[2147] This section aims to establish a technique to enable multiplesimulators to cosimulate with each other without having to rewritesimulator-specific plugin code.

[2148] It should be possible to makesimulation-accuracy/simulation-speed trade-off decisions, so thatdifferent parts of the cosimulation execute with the desired degree ofaccuracy/speed.

[2149] User of the simulators used in cosimulation should be able towrite (in Handel-C, VHDL, C or whatever) the models being simulatedindependently of any other part of a cosimulation arrangement. This mayenable reuse of models from one cosimulation arrangement to another.

[2150] Issues

[2151] Logic values

[2152] High-impedance/tri-state simulation:

[2153] Some support for high-impedance states are beneficial for makingsimulation components modular when buses (or other wires that may bedriven by different components at different times are involved.

[2154] Internal resistance:

[2155] Helps model pull-up/pull down resistors, and keep modelsindependent for digital circuits three levels should be adequate: zero,infinite, and ‘some’.

[2156] ‘Unknown’ values:

[2157] If a floating input is read the result may be unpredictable,similarly if a circuit with a pull-up resistor is linked to a circuitwith a pull-down resistor, there's nothing driving the circuit. In thesesituations rather than picking an arbitrary result, propagating an‘unknown’ result may be more informative.

[2158] 9 valued logic (U,X,O,I,Z,W,L,H,−)

[2159] (uninitialized, strong unknown, strong 0, strong 1, hi impedance,weak unknown, weak 0, weak 1, don't care)

[2160] VHDL, Swift/OMI, IEEE 1164

[2161] 4 valued logic (0,1,Z,X)

[2162] Verilog, SystemC

[2163] 2 valued logic (0,1)

[2164] Cynlib, Handel-C

[2165] 120 valued logic!

[2166] Verilog OMI, IEEE 1364,

[2167] (Most of these are derived from permutations of different degreesof uncertainty of the values and strengths of values, each value isrepresented by a strength0 component combined with a strength 1component. The strengths range from: Supply, Strong, Pull, Large,Medium, Small, HiZ)

[2168] Using a two-valued system is fastest, but not entirely accurate.If one wishes to be able to determine if an LED may light up, he or sheneeds to be able to distinguish high-impedance from a logic zero. Beingable to represent high-impedance also enables one to identify if twocircuits are trying to drive a wire at the same time and flag this errorto the user. High-impedance is also useful when the direction ofinformation flow is not known. This isn't an issue for data-buses forexample, as the write-enable line can tell one which way the data isflowing, but if he or she wished to model a switch linking two busestogether, a simple two-valued logic system would run into trouble.

[2169] For fast simulation of correct circuits where logic values areused purely for passing information (not lighting up LEDs etc.) and thedirection of information flow is known by the connected circuit elementsthen two-valued logic is sufficient.

[2170] Event-based and cycle-based Simulation:

[2171] Some simulators are event based (ModelSim) some arc cycle based(Handel-C, ARMulator, SingleStep). Event based simulation is moregeneral as it determines on-the-fly what needs to be simulated when.State based simulations run according to a predetermined order ofexecution, this may give them a speed advantage.

[2172] When integrating event-based simulators, the ideal order ofexecution is not obvious. If one considers the following cosimulationarrangement:

[2173]FIG. 44A illustrates a pair of simulators 4450, in accordance withone embodiment of the present invention. In this diagram, the dottedline 4452 represents dependencies, and the solid arrows 4454 areconnections between simulators. If both simulators were cycle-based thenthe ideal order of execution would be one which didn't require eithersimulator to repeat a simulation cycle. This is achieved bysynchronizing the simulators at a fine-grain enough level for changes inA to propagate down through to E in one simulation cycle. Thisscheduling order can be referred to as being Interleaved.

[2174] If both the simulators in the above arrangement were event-based,the natural order of evaluation would be to have each simulator wait forchanges on their inputs, and then propagate the effects of these changesto their outputs. Thus simulators 1 and 2 each execute three and fourtimes respectively. This scheduling order can be referred to asFully-propagated.

[2175] If one simulator were cycle-based and one event-based, then thecycle-based simulator may be quicker if one uses a relativelyfine-grained level of synchronization and only simulate the cycle once.However the event-based simulator may benefit from getting all itsinputs at once and not one at a time. The work required by anevent-based simulator to propagate the effects of the input-events tothe outputs may be duplicated by feeding inputs in one at a time. Alsoif multiple input-events occur at once, they may cancel each other outin a way that saves an expensive computation. For example, if two inputsare fed into an xor gate, the output of which triggers some expensivecomputation, then if both inputs to the xor change, it makes a bigdifference if they occur simultaneously or sequentially.

[2176] When cosimulating with event-based and cycle-based simulators itmay be desirable to enable the user to decide whether the simulatorscheduling used should be most suited to cycle-based or event-basedsimulators. One can make an event-based simulator look like acycle-based one, and a cycle-based simulator look like an event-basedone, the question is which approach is best, and the answer is likely tobe different in different circumstances. Supporting hardware emulators:

[2177] Using hardware to emulate a target board is common practice.However co-simulation is done, it shouldn't preclude the possibility ofmixing hardware emulation with software simulation.

[2178] Multi-processor Systems:

[2179] The cosimulation methods used should be able take advantage ofmultiple processors and possibly multiple computers. The extent to whichparallelism can be exploited is influenced by the proportion ofcomputation to communication/syncronisation. Synchronization over anetwork is viable, despite potentional of communications overhead. Acost-benefit analysis may be necessary prior to implementation. For veryfast simulators, the communications overhead of synchronizing thesimulators may be greater than the benefits gained when dealing with twoprocesses on the same multiprocessor computer. However without radicalrestructuring of the implementations of all (but one) of the simulatorsbeing used, one may incur the possible synchronization overhead.

[2180] Buffering Communication Between Simulators:

[2181] When the degree of communication between simulators is low,allowing the simulators to run ahead of each other can reduce the amountof context switching between processes and increase simulation speed.Using a cosimulation scheme which doesn't preclude such optimizationsmay be beneficial. When debugging, having simulators running ahead ofeach other may cause problems, if the simulator lagging behind reaches abreakpoint before catching up with the other simulator, then the usermay see the two simulators in an inconsistent state.

[2182] Starting and Identifying Simulators:

[2183] Whether the user should manually start each simulator or whethera co-simulation program should launch them is also an issue. If twoinstances of the same simulator are automatically started then they canbe passed arguments through environment variables so they identifythemselves to the co-simulator program. If the simulators are manuallystarted from the start menu, they may gain their identity after theyestablish communication with the cosimulation program.

[2184] A pool of simulators could be used to avoid repeated starting andquitting of simulators. When a cosimulation sessions ends, thesimulators would enter a pool of available simulators ready for anothercosimulation session. Simulators typically provide a window wherearbitrary output can be sent, this would be used to indicate whichsimulator was doing what.

[2185] Automatically Controlling the Simulators

[2186] Ideally the state of a simulator could be controlled on startupand during execution. For example to simulate the Kompressor board onstartup one doesn't want to have to require the user to load up threedifferent programs for the two FPGAs and the processor.

[2187] Similarly when the one FPGA or the processor reconfigures theother FPGA one doesn't want to involve the user. SingleStep and ModelSimboth provide scripting languages which may help in these situations. Thememory in the ARMulator can be set by plugins, but there doesn't appearto be a way for plug ins to change the associated symbol tables anddebugging information. Handel-C doesn't enable plugins to change thecircuit currently being simulated.

[2188] Integrating Simulator GUIs

[2189] It's relatively easy to co-simulate simulators together by havingeach pretend to be peripheral hardware plugged into the others. Eachsimulator thinks it's in charge, and has no knowledge that other fullyfledged simulators with their own GUIs are being used for the pluginperipheral hardware. If one wishes to be able to use the debuggingfunctions of one GUI to control all the simulators, then the pluginsneed a way to pause and resume the simulators. A fudge would be to havethe plug ins prompts the user to pause and resume the simulators, butthis would quickly become tedious and annoying. ModelSim enables pluginsto pause the simulation, but it doesn't enable them to resumesimulation. Other simulators (Handel-C, ARMulator, SingleStep) don'tallow plug ins to pause simulation.

[2190] Another issue arises from the different simulators allowingsimulation to stop at different times. SingleStep only allows simulationto stop between instructions. Handel-C only allows simulation to stopbetween clock cycles, ModelSim allows simulation to stop anywhere. Thiswould be a problem for example when one wishes to advance time by lessthan a clock cycle in ModelSim, if the ModelSim simulation relied onasynchronous circuits simulated by Handel-C then the Handel-C GUI wouldnot be available mid clock cycle. It may also be a problem whencosimulating two microprocessors if the instructions on differentmicroprocessors don't start and finish on the same clock cycles.

[2191] Depending on the level of communication between two simulators,it may be possible to allow one to run ahead of another so both can bestopped, this may be confusing for the user though, as each simulatorwould have a different idea of what the time was.

[2192] Integrate with Other Vendors Cosimulation Tools

[2193] Synopsys, Mentor Graphics, Cadence, Innoveda and Arexsys allprovide cosimulation tools (Eaglei, Seamless, Affirma HW/SW Verifier,Virtual-CPU and CosiMate respectively). These enable the integration ofa variety of HDL simulators with Instruction Set Simulators (ISS).

[2194] The cosimulation tools from Synopsys' Eaglei, Mentor Graphics'Seamless and Arexsys' CosiMate all provide support for a wide range ofHDL simulators. Processor support for Synipsys' Eaglei and MentorGraphics' Seamless is provided mostly though Mentor Graphics' XRA Ydebuggers, and Arexsys' CosiMate support “a wide range of C debuggers”.Integrating the Handel-C simulator into one or all of these cosimulationtools is possible.

[2195] There's a fair amount of documentation on Mentor GraphicsSeamless CVE (CoVerification Environment). One important aspect ofSeamless is the way it can speed up execution by reducing the amount oftime spent simulating hardware. This enables the ISS to proceedunhindered for a significant amount of time. Minimizing hardwaresimulation is done through a number of optimizations: data accessoptimizations, instruction fetch optimizations and time optimizations.The data access and instruction fetch optimizations prevent the hardwaresimulator from seeing bus activity during bus- cycles it is notinterested in. The hardware simulator is however still advanced in time.The time optimizations effectively stop the hardware simulator seeingclock changes during bus-cycles it is not interested in, this enablesthe ISS to be run for many cycles at a time without context switching.

[2196] For a cycle-based simulator like Handel-C, the data access andinstruction fetch optimizations would make no difference, the simulatorhas just as much work to do whether it sees changes on the bus or not.The time optimizations would make a difference. Knowing when it is safeto use time optimizations is not easy, Seamless CVE allows the user toenable or disable time optimizations according to how the memory isbeing accessed, whether this still maintains simulation accuracy is leftto the user to decide. If it were possible to automatically know when asimulator had reached a stable- state then the time optimizations couldbe made more reliably and generically, rather than relying on CPU memoryaccess to give hints. Possibly a user could modify their design to tellthe cosimulation tools when their design had reached a stable-state andwould only need to see another clock change when something else changedin a relevant way as well.

[2197] Cosimulation via OMI

[2198] The Object Model Interface is an interfacing standard (IEEE1499), which enables models written using one tool to be incorporatedinto another. Tools known as Model Compilers or Model Packagers take aVHDLNerilog/C description of a model and turn it into object code whichis OMI compliant and can be imported into other simulation tools. OMIprovides a means for IP vendors to provide simulation models of their IPwithout giving away the source code. By being an open standard OMI alsoincreases interoperability.

[2199] OMI was created by the Open Model Forum. Synopsys, MentorGraphics and Cadence were all involved in the process. OMI combines twoAPI's, a simulator-API and a model-API. The simulator-API is based onSWIFT from Synopsys and deals with interfacing models to the rest of asimulation. The model-API is based on a proposal from Cadence and isconcerned with the internal workings of the models. Cadence productsalready support OMI, several other vendors have pledged to support itsoon. Use of SWIFT is currently more common than OMI, but SWIFT maybecome a legacy standard.

[2200] OMI is a relatively complex standard and supporting it would be asizeable undertaking. It doesn't provide specific support forcosimulation and would quite possibly be a hindrance in optimizingcosimulation to run faster. It would be possible to involve OMI modelsin a cosimulation, but to use OMI interfaces as the sole means ofcommunication in cosimulation would most likely be overly restrictive.

[2201] Cosimulation with SystemC

[2202] It would be possible to use models written in SystemC in acosimulation arrangement. It may also be possible to use SystemC as themeans of integration of a number of models not written in SystemC.However as with OMI restricting integration to just that that can beachieved via SystemC is likely to be overly restrictive. Although thesource to SystemC is freely available, modifications to it can only bedistributed back to the SystemC committee. So improving SystemC tobetter support cosimulation of non-systemC models is not likely to bepossible.

[2203] Proposed Architecture

[2204] Two categories of simulation models are proposed, light-weightthread-sharing models and heavy-weight process-bogging models. They eachhave the following characteristics:

[2205] Light-weight thread-sharing models:

[2206] Implemented as a dll.

[2207] No blocking functions.

[2208] Able to instantiate and interconnect sub-models.

[2209] Heavy-weight process-hogging models:

[2210] Implemented as a separate process, requiring IPC forsynchronization/communication.

[2211] Not able to instantiate sub-models.

[2212] Light and heavy refer to the communication overhead of usingthese models, and not the simulation overhead of the models. Lightweight models would typically be used for implementing very simple gluelogic, clocks and optimization logic (see later). Heavy weight modelswould typically be used for wrapping up existing simulators which have aplug-in interface. However there would be no disadvantage in acomputationally intensive model using the light-weight model interface,in fact it would give the advantage of added flexibility when decidingwhich computations should be performed in which processes.

[2213] Execution of the cosimulation environment would consist a numberdistinct stages: instantiation, analysis and simulation. Instantiationbegins with a single root model, which would typically be a light-weightmodel which instantiates and connects up other models. This root-modelcould be a simple ‘C’ program or an elaborate GUI which allowed the userto interactively instantiate and connect up models. The modelsinstantiated have a hierarchical relationship, there is no global namingpolicy for the ports on a model. Models are only able to communicate viaports they have been given by their parent or children.

[2214] After initialization is complete an automatic analysis stagebegins. The hierarchical relationship becomes irrelevant and theinterconnections between models are analyzed as an unstructured network.At this stage the cosimulation tool builds up any structures it may needat simulation time. Optimizations like static scheduling decisionsbelong here. During simulation dynamic scheduling decisions are made,process-hogging models are synchronized with each other, communicationbetween models is handled.

[2215] Processes and DLLs

[2216]FIG. 44B illustrates a cosimulation arrangement 4462 includingprocesses and DLLs. The present figure shows three processes 4464, eachprocess contains a program 4466 and a number of dlls 4468.

[2217] The Cosim HQ program starts everything off. It starts off theroot model which is a light-weight model existing as a dll in the sameprocess as the Cosim HO program. This model then instantiates andconnects other models. Other light-weight models are simply loaded intothe same process.

[2218] Starting up process-hogging models is a little more involved. Fora light-weight model to instantiate a process-hogging model, thelight-weight model may know the name of a simulator specific launcherdll. This name is passed to Cosim HO which gives the launcher dlldetails of how IPC is to be achieved. The launcher dll then loads up thesimulator which may at some point load up the simulator specific cosimplugin, which loads up a generic cosim dll. The simulator specificlauncher and cosim plugins may cooperate is passing the IPC connectioninformation from Cosim HO to the generic cosim dll. Once this has beenachieved communication between the two processes can take place. Thetechniques described here avoid the simulator specific plugins needingto know how IPC takes place, and avoids the cosimulation program needingto know how to start up and pass parameters to every different kind ofsimulator.

[2219] Communication may take place between processes on one machine, orbetween multiple machines across a network, only cosimulation specificcode needs to be concerned with this. The simulator specific codeneedn't be concerned.

[2220] Similarly any mechanism may be used to pass connection detailsfrom the launcher dll to the generic cosim plugin, such as command linearguments, environment variables, shared memory, files or whatever, andonly the simulator specific code needs to know about it, not thecosimulation code.

[2221] Light-Weight Models

[2222] Light-weight models can be used for models which arecomputationally cheap and which one wants to keep isolated from othermodels. For example a clock, one wouldn't want a separate process justto contain a clock model, but he or she wouldn't want to have toarbitrarily pick another model in which to put the clock, as this wouldhinder interoperability between models. Light-weight models can also beused for optimizations such as preventing a hardware simulator seeingthe clock when a CPU is doing something unrelated to the hardware.

[2223] Light-weight models needn't exist in the same process as theCosim HO program. The Cosim HO program and the generic cosim dlls mayconspire between them to achieve the desired execution order in anywaythey please. One could migrate light-weight models out to otherprocesses. For example if an ISS is able to simulate many cycles withouta hardware simulator being involved, it would be desirable for the clockgeneration code to be in the same process as the ISS. If the genericcosimulation dll is clever enough then communication between theprocess-hogging simulators and the cosim HO may be reduced or eliminatedaltogether, thus reducing the number of context switches. Each processloading the generic cosim dll may become capable of direct communicationwith other simulators, communication needn't go via the cosim HO.

[2224] Optimizations

[2225] Light-weight models can be used to shield a hardware simulatorfrom details it doesn't need to see. If a light-weight model is placedbetween ISS and hardware simulator, then with some configuration thelight-weight model can use address decoding to determine whether thehardware simulator needs to run or not. Knowing when its safe to notclock the hardware simulator is application specific. A pathologicallyunoptimizable example would be using hardware to profile a CPUsactivity, in most cases though significant optimizations should bepossible.

[2226] Application Programming Interfaces Exchanging Interfaces

[2227] The interfaces between programs and dlls are defined by a numberof header files. There may be a number of interfaces between a givenprogram-dll/d li-dll pair. Each program or dll provides a mechanism bywhich an interfacing program/dll may request access to a namedinterface. Before an interface may be requested though, the mechanismsby which interfaces are obtained are exchanged between the communicatingprogram/dlls.

[2228] typedef void* GetInterfaceT(void* state, char* ifname);

[2229] intExchangeInterfaces(GetlnterfaceT*,void*,GetlnterfaceT**,void**);

[2230] The dll being loaded implements ExchangeInterfaces, theinitiating program Idll calls ExchangeInterfaces with a function whichthe dll being loaded may call to obtain interfaces. It also passes avoid pointer which should be passed to the GetInterface functionwhenever it is called. This void pointer may point to anything theinitiating program Idll wants, including NULL if the initialing programIdll has no use for it. The initiating program Idll also receives back acorresponding GetInterface function and associated void pointer.

[2231] Accessing interfaces by name makes it possible to add newinterfaces and support multiple versions of an interface. If interfacenames were ever to be created outside Celoxica, the names couldincorporate GUIDs (Globally Unique IDentifiers) but this seems unlikelyto be necessary.

[2232] Interfaces

[2233] For interfacing between models there are three kinds ofinterface:

[2234] Init—for initialization and termination

[2235] CommSync—for communication and synchronization

[2236] Control—for cross-model breakpointlstop/start control

[2237] These interfaces are implemented for each of the three modeltypes:

[2238] Light

[2239] Event

[2240] Cycle

[2241] Each interface has two sides a simulator side and a cosimulationside. Also there is an interface for using the launching dlls. Thisgives a total of 19 interfaces. Each interface has a structurecontaining function pointers to the functions that interface maysupport. To implement an interface the programmer may create an instanceof the required structure. The 19 interface structure types are listedhere:

[2242] Init-CoCycle-IFT

[2243] Init-SimCycle-IFT

[2244] CommSync-CoCycle-IFT

[2245] CommSync-SimCycle-IFT.Control-CoCycle-IFT

[2246] Control-SimCycle-IFT .Init CoEvent IFT

[2247] Init SimEvent IFT --

[2248] CommSync-CoEvent-IFT

[2249] CommSync-SimEvent-IFT .Control CoEvent IFT

[2250] Control SimEvent IFT --

[2251] Init-CoLight-IFT

[2252] Init-SimLight-IFT

[2253] commSync-CoLight-IFT

[2254] CommSync-SimLight-IFT.Control_SimLight_IFT

[2255] Launch SimProcess IFT

[2256] The functions defined in these interfaces are detailed in theheader files: cosim-light.h, cosim-event.h, cosim-cycle.h,cosim-launch.h. If the ability to simultaneously save and restore stateacross a number of simulators is to be implemented then furtherinterfaces may be defined.

[2257] Datatypes

[2258] Initially this embodiment may only support 2 and 4 valued logicvalues. When ports are declared the they may have a type associated withthem. These types are represented by abstract C values, these are eitherpredefined e.g. hitType , logic4Type, logic9Type, int64Type , int32Type,int16Type, int8Type, realType, douhleType. Also there are a number offunctions enabling the user to create vector types e.g. mkBitVectorT(uint), mkLogic4VectorType (uint), mkLogic9VectorType (uint) Finally ifthe user wishes to use another type altogether they may create their owntype with the function userType (char* name, int size), so long as otherparts of a cosimulation arrangement agree on how large this user typeis, the cosimulation tool may allow them to do what they like with dataof this type.

[2259] Values are given the abstract type ValueT. This is a voidpointer, for bit-vector types it may point to a memory locationcontaining bits packed into bytes, i.e. a 32-bit long bit-vector mayjust be 4 bytes in memory. For 4-valued logic vectors, ValueT may pointto a Logic4 VectorT struct containing two more pointers hitKind andhitValue. hi tKind and hitValue each point to bits packed into bytes inmemory for a given bit location the values in hi tKind and hi tValuedetermine the 4-valued logic value as follows in Table 2. TABLE 2HitKind hitValue 4-valued logic 0 0 Z 0 1 X 1 0 0 1 1 1

[2260] This enables very quick checks to be performed to see if anentire logic-vector consists of Os or 1s, or to check if an entirevector is in a HiZ state. This is useful as typically a bus may eitherbe fully driven or fully floating. (The implementation of SystemC makesthis sort of check a much slower process). The header file cosim-types.h contains the type declarations and function prototypes for declaringand using types in cosimulation.

[2261] When converting from 4-valued logic to 2-valued logic one havesome freedom in converting X and Z values. Options include alwaysconverting them to 0, converting them to the previous value so as tominimize events, and converting them to a random value in order tostress test a model. Or one could consider an attempt to read an X or Zto be an error, and flag it at run-time.

[2262] Initialization

[2263] Cosimulation always starts off with one root model. As only lightmodels can instantiate child-models the root model may be a light modelif any more than one model is to run. During instantiation a model maycreate ports of any type and declare dependencies between these ports.Once a child model is instantiated, the parent may examine which portsthe child created, and may then connect the ports to any other(type-compatible) ports.

[2264] Simulation

[2265] After the hierarchy of models created during initialization havebeen flattened out to a non-hierarchical network, simulation can begin.Cycle based models call functions in the CommSync interface to read andwrite ports when ever they want, synchronization is achieved by blockingthe returns of these functions calls. Event based simulators, outputwhen ever they want, and request to be informed of input events whenthey are ready for them. Light-weight models are implemented asevent-based models, and no functions are allowed to block. Simulatorsare able to register wake-up calls for simulating internally timedlogic, the simulators may be woken up earlier if another simulatortriggers off an event.

[2266] Launching

[2267] It is the responsibility of the programmer integrating asimulator with the cosimulation tool to write a launch dll. This dllwould typically startup a new simulator process but it doesn't have to,it could pick an already existing simulator from a pool if idlesimulators. If a simulator disconnects from a cosimulation arrangementearly, then the launch dll may be called in the middle of simulation toresurrect the disconnected simulator. This resurrection would benecessary in situations like a user resetting a Handel-C program.Handel-C terminates all plugins and then restarts them when resetting aprogram. For this not to have adverse effects on the cosimulation, thecosimulation tool may allow a simulator to disconnect and reconnect aslong as it declares just the same ports with the same names, types anddependencies. One could use the dynamic relaunching as a means ofhot-swapping simulators, but that's not what it's meant for.

[2268] The launching dll should assume it is to start the simulationprocess on the same computer it is running on. If the Cosimulation toolwishes to run a simulator on another host, the cosimulation tool mayitself be responsible for running the launching dll on the remote host.The launching dll may be given connection info which should be passed onvia the simulator and the simulator specific plugin to the generic cosimdll, which may understand the connection info and establish a connectionback to the cosim tool over the network, and possibly other genericcosim dlls on other hosts.

[2269] Alternatives

[2270] Instead of allowing child models to declare whichever ports theywant, and have the parent model figure out how to wire the ports up, onecould have the parent declare a number of signals and pass these tochild processes. By passing the same signal to more than one child modela connection would implicitly be made. It would then be theresponsibility of the child to check the signals passed in wereappropriate. Declaring signals first is less suited to an interactivegraphical instantiation and connection tool. A user would probably findit easier to instantiate a model and see which ports they got back,rather than having to correctly predict which ports a child model maywant. One could provide both techniques together. SystemC allows signalsto be passed into and ports to be passed back from a model beinginstantiated, CynApps only allows signals to be passed into a model. Itsprobably best to stick to the relatively simple technique of allowingchild models to create which ever ports they like, until advantages ofenabling both techniques are found in practice.

[2271] SystemC allows models to be implemented in either a non-blockingway similar to the light-weight models described here, or to usecooperative non-preemptive multi-threading to allow multiple models toexecute in a relatively light-weight manner without OS calls. This kindof multi-threading may make it easier to write more complex light-weightmodels, however apparently it makes execution slower. This kind oflight-weight threading may be worth supporting if people outsideCeloxica are going to write moderately complex light-weight models.

[2272] Further Work

[2273] There are three different levels of user for this cosimulationtool:

[2274] People integrating new simulators

[2275] People writing light-weight models

[2276] The final users of a cosimulation arrangement

[2277] Documentation needs to be provided for each of these types ofuser. The documentation for the final users may contain simulator andarrangement specific parts. Different kinds of optimizations need to beexperimented with. Optimizations in other cosimulation tools have arisenout of necessity following experiences with simulation that just run tooslow.

[2278] Cosimulation Algorithms and Programming Interfaces

[2279] This section explores different algorithms that could be used forcosimulating any number event-based and cycle-based simulators and theimplications this has on the programming interfaces used. The presentsection considers three types of simulator:

[2280] Event-based, such as ModelSim

[2281] Cycle-based synchronous, such as SingleStep and ARMulator wheresimulation of asynchronous logic is not performed and cycles cannot berepeated

[2282] Cycle-based asynchronous, such as Handel-C and probably otherCycle-based simulators such as Cyclone (Synopsys HDL simulator), hereasynchronous logic can be simulated, and simulation cycles can berepeated as necessary.

[2283] If cosimulation with simulators which simulate asynchronouslogic, but don't allow cycles to be repeated is required, then somecosimulation arrangements may be unsimulatable, it may be necessary togive compile-time or run-time errors in these circumstances. Allsimulators may either only simulate untimed logic or may provide a meansby which a cosimulation plug in can find out when the next event is dueand provide earlier stimulus if necessary.

[2284] These different types of simulator may be wrapped up so as toenable communication between different simulators. This wrapping maymake each simulator look like an event based simulator and may containadditional information and interfaces to help in scheduling simulatorexecution.

[2285] Scheduling Event-based Simulators

[2286] Wrapping up event based simulators to look like event basedsimulators is relatively easy. Issues involve propagating input eventsand detecting output events. It doesn't appear to be possible for aplugin to instruct ModelSim to process all current events withoutadvancing simulation time. Advancing simulation time by a very smallamount is one solution to this, so long as repeated simulation doesn'tresult in these small amounts adding up to something significant.ModelSim can be instructed to call callback routines whenever a signalchanges.

[2287] Scheduling Cycle-based Synchronous Simulators

[2288] Cycle-based synchronous simulators (such as an Instruction SetSimulator(ISS)have a very fixed idea of the order in which evaluationshould proceed. Fortunately as they do not simulate asynchronous logicit is never necessary to request such a simulator to resimulate a cycle.Cycle-based synchronous simulators are sensitive only to activeclock-edges, all other changes can be ignored. Wrapping such a simulatorup as an event-based simulator is straight forward.

[2289] Scheduling Cycle-based Asynchronous Simulators

[2290] There are a number of different ways for execution of acycle-based asynchronous simulator to proceed. Here one can explore somedifferent scheduling policies.

[2291] Ideally when wrapping such a simulator up as an event-basedsimulator the clock input shouldn't be treated as a special case. Asimple approach would be to wait for an input event to arrive, and thenadvance the simulator far enough for the effects of the input change topropagate to all dependent outputs. If there are no current input eventspending then advance simulation time, until the next future event isscheduled, this may typically cause a clock input to a cycle-basedsimulator to change, but in general it could be any input.

[2292] ASAP I Eager Simulation

[2293] One need not know which outputs depend on which inputs, one canbe conservative and assume all outputs depend on all inputs. When asimulator gets the chance to run again, it can check to see if anyinputs have changed and if so advance far enough for all outputs to beupdated.

[2294] This approach to simulation makes no assumptions about the orderin which the cycle-based simulator gets and sets inputs and outputs, itmakes no assumptions about the dependencies between inputs and outputs.It does not require the concept of a start of simulation cycles and theend of a simulation cycle. As each outputs is recomputed by thesimulator, one can check to see if it has changed, and if so propagatethe effects to other simulators. The order in which the simulatorsexecute is not too critical. One could run just one at a time, or allsimultaneously.

[2295] Simulation in Turns

[2296] If running just one simulator at a time, all simulators but onewould be stopped using OS-level wait operations, just one would proceed.When finished one can check if any other simulators need to execute, ifso pick one arbitrarily to go next, otherwise advance simulation time.

[2297] Simultaneous (multi-processor) Simulation

[2298] If cosimulating two low-computation/high-communication simulatorson a multiprocessor system then one could get away with fewer OS-levelcalls. One could have a simulator running on each processor. Nosynchronization would be needed for passing word sized data between thesimulators. For larger data transfers, busy-wait mutual exclusiontechniques would be an efficient mechanism for maintaining dataintegrity. Each simulator would loop as fast as it liked until none ofits inputs changed, then it would use an OS-level wait function to waitto see if any of the other simulators subsequently changed the inputs.

[2299] When all simulators reach this waiting state then simulation timecan advance, typically causing a clock signal to change. Semanticimplications of evaluation order These two techniques could result indifferent results being computed depending on the order in whichsimulators execute. For example if one simulator is going to change twooutputs from (1,0) to (0, 1 ), and another simulator is going to ANDthese two values together, the order in which the two simulators readand write these values may affect the result. The output of the AND maypulse high for an infinitesimally short length of time, or it might not.If some circuit counts these pulses then the implication could compound.These problems could only occur in badly designed circuits, the issuesinvolved are inherent in true hardware as well and so may be in anysimulation of it. (VHDL is able to claim to have precisely definedsemantics by dictating what is computed when. However this results inwhat might be thought of as semantics preserving transformations such assplitting a signal in two, not being semantics preserving. Again this isonly an issue for badly designed circuits).

[2300] Just-in-time I lazy I Interleaved Simulation

[2301] Busy waiting might be worth while when one has at least as manyprocessors as simulators wishing to busy wait, and one doesn't want touse the computer for anything else at the same time, but for mostcircumstances it would be unsuitable.

[2302] The simulation-in-turns approach while simple and general couldresult in much more work being done than required. FIG. 44C illustratesan example of a simulator reengagement 4470, in accordance with oneembodiment of the present invention.

[2303] These two blocks represent hardware simulated by two connectedcycle-based asynchronous simulators 4472. The dashed lines representasynchronous logic, although at the cosimulation level one may not knowwhere the asynchronous logic is. If one uses a simulation-in-turnsscheduling policy then one updates all outputs from simulator 1 and thenupdate all outputs from simulator 2. If it is assumed that eachsimulator reads and writes their inputs and output in the orderA,B,C,D,E, then the input B to simulator 1 may change after bothsimulators have simulated one cycle, so another simulation cycle ofsimulator 1 is performed, which triggers another simulation cycle insimulator 2 and so on. In all each simulator has to repeat the samesimulation cycle three times.

[2304] In the example above it seems obvious that each simulator needonly simulate each cycle once, one just need to use a finer level ofsynchronization. However it's not always the case that each simulationcycle need only be performed once. If the inputs and outputs of theasynchronous logic was fed to a device which was being clockeddifferently then it may be necessary to repeat a simulation cycle.Instead of repeating a simulation cycle every time an input changes, onecan delay calculating outputs until the output is required. This enablesone to ignore changes to the inputs if no one is going to read theoutputs. This is safe as long as the asynchronous logic is non-cyclicand is thus unable to form latches or registers, if registers existed inthe asynchronous logic then the logic could count the number of times aninput changed, however this falls within the realms of badly designedhardware.

[2305] In the course of simulating one cycle, an input could change:zero times, once or many times. There's little point waiting for anyinput change before allowing a simulator to advance, a better schemewould be to wait until an output is required before advancingsimulation. Simulation output is required whenever time advances oranother simulator wishes to read the simulator's output. When an outputis required and new inputs have arrived since the last time that outputoccurred, the simulation is allowed to proceed to the point where thatoutput is produced.

[2306] In the above example evaluation proceeds in the following order:the clock changes, this invalidates outputs from the simulators, logicbetween the clock and all outputs is assumed, (if there were no suchlogic, that is if the outputs were purely dependent in inputs and notregisters, then evaluation would proceed in the same order but forslightly different reasons). sim1 advances past outputting A and blockson reading B, there's no point in delaying outputting A as it may be thesame however long one waits, but it may be worth while delaying readingB to avoid reading in a value which is going to change. Sim2 blocks onreading A, until sim1 attempts to read B (if sim1 has already reachedthis point then sim2 doesn't block). Once sim1 is blocked on reading B,and sim2 is blocked on reading A, sim2 is allowed to proceed until ittries to read C. The key here is that simulators may be suspended whiletrying to read input until the input is upto date. An input is out ofdate if it was produced by a simulator that has received new input morerecently that it produced the output. If only one simulator is trying toread upto date input, that simulator proceeds, if more than onesimulator is trying to read upto date input, then one could pick one orboth to proceed. If all simulators are trying to read out of date input,there may be some asynchronous cyclic logic, one may pick one simulatorto proceed, some asynchronous cyclic logic can be used in a well definedmanor where race conditions don't apply, if it is then which simulatorgoes first doesn't matter, otherwise one has another case of badlydesigned hardware, and the output in practice as well as in simulationwould be unpredictable.

[2307] So far we've assumed that within one cycle, all outputs aredependent on all inputs. Assuming the outputs are depend on all inputsmay be overly cautious, and may force more simulation cycles to berepeated than necessary. If the cosimulation API were able to capturedetails of such dependencies then the need to repeat simulation cyclescan be more accurately calculated.

[2308] Cosimulation Programming Interface

[2309] The information required by a cosimulation backplane to correctlyschedule simulators include:

[2310] Type of simulator: event based, cycle-based synchronous,cycle-based asynchronous.

[2311] Dependencies between inputs and outputs in models (optional)

[2312] The optional items may help more accurately calculate whensimulation cycles need to be repeated, but an approximation can be usedif the optional info is unavailable.

[2313] Its also necessary for the cosimulation backplane to know whathardware interfaces are being modeled by a simulator. For a hardwaresimulator the hardware interfaces being used could be almost anything,even for an instruction set simulator there is some configurability,such as bus widths and interrupt interfacing methods. There are two waysin which this information could be used by a cosimulation backplane:statically or dynamically. The implication of this is that when writingcode used by a cosimulation backplane to indicate how the simulatedmodels are connected together, one could either have details of themodels hardware interfaces checked at compile-time or run-time.

[2314] Compile-time checking would require automatic generation of CIC++header files from various simulator plugins, this scheme has the benefitthat coding mistakes resulting in hardware interface mismatches arespotted earlier, it wouldn't however result in faster simulation, sinceit may still be necessary to check the actual hardware interfaces usedby a simulator are the same as the ones expected by the cosimulationbackplane. A static hardware interface connecting approach may result insyntactically nicer code as actual CIC++ identifiers and struct namescould be used and not just names in strings to be connected up later.

[2315] Using a dynamic approach to hardware interface connections wouldremove the need for automatic GIG++ header file generation, allinterface names would be stored in strings and checked for validitylater. A dynamic approach would also be more suitable if thecosimulation backplane is to be configured using a GUI and not a CIC++program. The whole issue of how one starts up different simulators islikely to be a matter of personal taste, its probably best that thecosimulation API doesn't prohibit any mechanism, either by supporting anumber of startup techniques or by being neutral to the issue.

[2316] Cosimulation User Documentation

[2317] The present section explains how to use the cosimulation serverprogram, and how to use the client library.

[2318] Cosimulation Architecture

[2319]FIG. 44D illustrates a schematic of exemplary cosimulationarchitecture 4480. Cosimulation is split into two parts: a client 4482and a server 4484. The server co-ordinates the allocation ofsynchronization points (or sync-points) and shared memory. The clientsare the simulators one may want to use in cosimulation with pluginsusing the cosimulation client library. To start cosimulating, first thecosimulation server may be started, then clients may start and finish,allocate and deallocate cosimulation resources asynchronously withrespect to each other. Typically a cosimulation client may first make aconnection to the cosimulation server, then it may register anysync-points it wishes to use to synchronize with other simulators, andattach any shared memory it wishes to use to share data with othersimulators. The simulators may then communicate via the shared memoryand synchronize using the sync-points before detaching from the server.

[2320] Data Types

[2321] The following data types are used in the cosimulation clientlibrary:

[2322] typedef void CosimConnection;

[2323] typedef void SyncPoint;

[2324] typedef void (*CosimErrorHandler) (char* error);

[2325] CosimConnection and SyncPoint are actually structs but the userof the cosimulation client library may only be dealing with pointers tothem, CosimErrorHandler is used to register an optional error handler.

[2326] Connections

[2327] CosimConnection* CosimConnect(char* servername,CosimErrorHandlererrorHandler);

[2328] This function establishes a connection from the client to theserver.

[2329] servername

[2330] Specifies the name of the server, if null is passed “CosimServer”is used

[2331] errorhandler

[2332] Specifies a function the clients library functions should callwhen an error occurs. The error handling function is passed a textstring explaining the error. When the error handling function returns,the cosimulation library may terminate the process. If a null value isgiven a default error handling function is called which pops up amessage box explaining the error.

[2333] return

[2334] Returns a pointer to the opaque CosimConnection structure.

[2335] void CosimDisconnect(CosimConnection* connection};

[2336] This function closes a connection from the client to the server.Any cosimulation resources (e.g. sync-points and shared memory) thathave been allocated but not explicitly deal located may be automaticallydeal located when the client disconnects from the server. [the servermay automatically clean up if a client terminates without disconnectingfirst, this prevents one crashed simulator bringing the remainingsimulators to a stand-still]

[2337] Connection

[2338] The pointer returned by CosimConnect

[2339] Synchronization Points

[2340] Sync-points enable a number of simulators to synchronize witheach other at various points. When a number of simulators all wish tosynchronize at a certain point, the desired effect is that none of thesimulators proceed past that point until all the simulators concernedhave reached that point. Not all simulators have to synchronize at once,one can have only a subset of the simulators synchronizing. For asimulator to synchronize it may first register interest in a sync-point.When synchronization on that sync-point is desired all the simulatorswhich registered the sync-point may call CosimSync with that sync-point,only when they have all called this function may the function return.During registration sync-points are identified by integers, theseintegers would typically be defined by an enum in a common header file.[If the cosimulation becomes deadlocked, for example by twointerdependent simulators blocking on different sync-points, thecosimulation server may report a deadlock, this indicates a bug in theuse of the cosimulation client library]

[2341] SyncPoint* CosimRegisterSyncPoint(CosimConnection* connection,int syncPointId);

[2342] This function registers a simulators interest in a particularsync-point.

[2343] connection The pointer returned by CosimConnect

[2344] syncPointId For two simulators to synchronize at some point theymay both register SyncPoints with the same numeric id, these ids wouldtypically be defined by an enum in a shared header file.

[2345] return Returns a SyncPoint pointer. This pointer is used in callsto CosimSync. void CosimUnregisterSyncPoint(CosimConnection* connection,SyncPoint* synePoint);

[2346] This function is used by a simulator to unregister sync-points,unregistering sync-points is handled automatically when CosimDisconnectis called [and also when a simulator crashes], so calls to this functionare not typically needed.

[2347] Connection The pointer returned by CosimConnect

[2348] SyncPoint The pointer returned by CosimRegisterSyncPoint

[2349] void CosimSync(SyncPoint* syncPoint);

[2350] This function is called by a simulator when it wishes tosynchronize with all the other simulators which registered thissync-point. Until all the simulators which have registered a particularsync-point call this function with that sync-point, none of the callsmay return.

[2351] syncPoint The SyncPoint pointer returned byCosimRegisterSyncpoint

[2352] Shared Memory

[2353] Functions are provided to assist in sharing memory betweensimulators. Simulators may attach and detach shared memory. Whenattaching memory the memory is identified by an integer. This integerwould typically be defined by an enum in a common header file. Whendifferent simulators attach to memory using the same memory identifierinteger, they gain access to the same shared memory. The cosimulationserver issues a warning if the same memory is requested but withdifferent sizes. Typically detaching is unnecessary as all resources aredeal located automatically when a simulator disconnects from thecosimulation server [and when any simulators crash].

[2354] So long as at least one simulator has a given piece of memoryattached, that memory is available to be shared by other simulators,when no simulators have a given piece of memory attached that memory islost, and new requests for memory by the same memory identifier integermay result in new memory being allocated, possibly with a differentsize.

[2355] void* CosimAttachMemory(CosimConnection* connection, unsignedmemId, unsigned size);

[2356] This function attaches a simulator to shared memory identified bythe integer memId.

[2357] connection The pointer returned by CosimConnect

[2358] memId An integer used to identify a piece of shared memory

[2359] size The desired size of the shared memory

[2360] return A pointer to the shared memory voidCosimDetachMemory(CosimConnection* connection, void* memPtr);

[2361] This function detaches a piece of shared memory from a simulator.Calling it is typically unnecessary as shared memory is automaticallydetached when CosimDisconnect is called.

[2362] Connection The pointer returned by CosimConnect

[2363] MemPtr The pointer returned by CosimAttachMemory

[2364] Cosimulation Server

[2365] The cosimulation server is a command line program which takes oneoptional argument, the name of the cosimulation server. This namedefaults to “CosimServer”. By specifying a different name, the multipleinstances of the same cosimulation environment can be run at the sametime without interfering with each other. A maximum of 63 clients mayconnect to one cosimulation server. The cosimulation server may warn ifsimulators try to attach the same piece of shared memory but specifydifferent sizes for that shared memory.

[2366] Multithreading

[2367] The CosimConnection pointer may be passed between threads withinthe process that called CosimConnect but not between processes. It isnot safe in general to use the same cosimulation connection in two callsof cosimulation client library functions at the same time, multipleconnections from the same process may be established.

[2368] SingleStep/Handel-C Integration Possibilities

[2369] Using the SingleStep MMK interface its possible to have Handel-Cmodel a memory mapped device, raise interrupts, operate in a DMAfashion, and as a coprocessor communicating via special processorregisters. It's also possible to override any SingleStep implementationof MMUs, Caches and Bus Interface Units.

[2370] Cosimulating by keeping two simulators running in lock-stepprovides a clock cycle accurate simulation of a CPU and FPQA. Also, itenables unusual things like non-invasive profiling of the CPU to seewhich instructions and memory are most heavily used. A custom-madememory management unit may also be enabled.

[2371] Improvements that Would Make Simulators more Amenable toCosimulation

[2372] As an option, it may be one object of the present invention toprovide an interface which would enable information about and control ofa simulators debugging interface. Before starting a cycle, a debuggershould check with all other debuggers that they do not wish to break onthis cycle. If one breaks, they all break.

[2373] When the user instructs one simulator to resume execution, allshould resume execution. This is slightly more complex to achieve. Asimple approach would be to have each debugger, when suspended, poll aplugin function every 0.1 seconds to see if execution should be resumed.The figure, 0.1 seconds, is a compromise between user interface latencyand wasting CPU cycles. A more responsive, less wasteful but morecomplex solution would be to have each debugger support some form ofasynchronous interaction with their plugins. Such asynchronouscommunication could be achieved by having plugins spawn a new threadwhich is permitted to send a Windows user message to the debugger,indicating that some plugin function should be called. Thus messagesfrom the plugin can be received in the same queue as QUI messages. It isprobably also possible to have the debugger simultaneously wait forwindows messages in a queue and wait for an event to become signaled.

[2374] As an option, it may also be an object of the present inventionto decouple a debuggers QUI from its simulator back-end. This would makefurther architectural changes easier, such as placing multiplesimulators in the same process and using inter-process communication tocommunicate between each simulator and its respective QUI. Forsimulators with a high degree of communication relative to computation,placing the simulators in the same process would be helpful. A suitabledecoupling of QUI's from simulators would enable a variety ofcosimulation arrangements possible. Another possible arrangementsuitable for multi-processor machines would be to use busy waiting tosynchronies simulators. So long as one has as many processors as onedoes simulators, execution may proceed faster then using OS basedsynchronization primitives. The point here really is that manycosimulation architectural arrangements are possible. A suitabledecoupling of QUI from simulator may prevent being tied to anyonearrangement and enable a variety to be used as future environmentsrequire.

[2375] As an option, it may be still another object of the presentinvention to make a simulator suitable for a wide variety ofcosimulation architectures. The simulator should in effect be turnedinside-out. That is, the simulator should provide a number of functionswhich each return as quickly as possible, these functions are thencalled by a host program which may be responsible for ensuring asuitable order of evaluation. It would be the host program that would beresponsible for integrating two simulators in one thread. The hostprogram may also use multiple threads and communicate either viaOS-based synchronization primitives or busy waiting. The simulatorswould have no awareness of the environment in which they are executing,and thus could be used in a variety of environments. If a simulatorwishes to wait for something such as user interaction or a networkconnection, it should do so in a non-blocking fashion by telling thehost program (via a return value or call-back). This enables multiplesimulators to be waiting at the same time.

[2376] Generic Cosimulation Architecture

[2377] As a further option, it may be an object of the present inventionto link a number of simulators together in a generic way. Such anability could be provided via a programming interface and/or a GUI. Anumber of issues are involved here. Two important issues includeidentifying what hardware a simulator is simulating, and ensuringexecution proceeds in a suitable order. Most simulators are capable ofsimulating a number of hardware components. Even something asspecialized as a microprocessor simulator can model processors whichhave different bus widths or a different number of interrupt lines. Thismeans one may not know until the simulators are running that they arecompatible with each other. For example, one may assume a bus is 16-bitswide and another may assume the bus is 32-bits wide. Having a means toautomatically determine the external characteristics (such as buswidths) of a hardware model is desirable. This may or may not requirethe execution of the simulator.

[2378] It should be noted that enabling a plugin to load up a differentprogram in a processor/net list in an FPGA could also be useful.

[2379] Cosimulation via SystemC

[2380] It may be possible to cosimulate using SystemC for joining upsimulators. However, there are a couple of issues which can't beanswered without looking further into the implementation of SystemC. Afirst issue involves whether the time at which SystemC verifies that thecomponents being plugged together are compatible. If this is atcompile-time, new C++ code may have to be generated for differenthardware models, e.g. processors with different bus-widths. Also, onedoesn't have much control over the order in which SystemC evaluatesthings. It may be desirable to modify SystemC to improve this matter.Unfortunately, SystemC licensing restrictions prohibit the distributionof modified SystemC code other than back to the SystemC committee.

[2381] Hardware Emulators Support

[2382] It might be worth looking into co-emulation That is, it may beuseful to consider using a processor and an FPGA on PCI boards. This maybe accomplished using either the same or different boards. BothSingleStep and ARM Developer Studio provide a similar environment formonitoring the state of emulation hardware as they do for monitoringsimulation software.

[2383] Clearly, the majority of the work would be on Handel-C. If theCPU and FPGA are communicating over the PCI bus instead of being on thesame board or communicating via a dedicated link between the two boards,it may be even more beneficial to enable either the FPGA or the CPU torun ahead of the other. While it may be possible to implement a MMU inan FPGA, one doesn't want to restrict simulation/emulation speed tolock-step speed just in case it might be needed. A hybridsimulation/emulation environment would also be a possibility.

[2384] Specific Improvements to SingleStep

[2385] It may be another optional object to provide better support forconsole interaction, and have a debugger jump to the front when abreakpoint is reached. This would provide better interaction when amemory access keeps returning MMKR-NOT-READYiO.

[2386] It may also be desirable to provide a call-back or mmk-accessreturn value which enables a mmk plugin to indicate the debugger shouldbehave as though it has reached a break point. The MMK plugin should beable to instruct the debugger to break on any clock cycle, even those inthe middle of a multi-clock cycle instruction.

[2387] One may also wish to make the GUI respond to a custom Windowsuser message which tells it to call a MMK plugin function. This functionmay then tell the debugger to advance one clock, or advance over nextassembler instruction/C line of code.

[2388] Plugins may be equipped with the ability to change the symboltable used by single step. In settings where an FPGA is going to changethe program code of a processor, it may be useful to have the C sourcecode reflect that change.

[2389] SingleStep has support for Multi-Tasking Debugging (Mill). Thisgives SingleStep awareness of an operating system. An OS specificlibrary may be used. There also exists a Mill Library Kit which enablesone to provide support for any OS. The SingleStep for MCore Targetsmanual gives partial documentation of the MTD Library Kit. It providescall back function which enables a library to call any command-linecommand. By issuing commands such as step and go, it may be possible togain some of the capabilities called for above.

[2390] Integrating the Handel-C Simulator with SingleStep

[2391] SingleStep provides two different API's for interfacing externallogic simulators to the CPU processors, the Peripheral API and theMemory Modeling Kit.

[2392] Memory Modeling Kit

[2393] The MMK API is an optional extra (presumably costing more). Itenables the user to replace the entire memory with their ownimplementation. The interface is clock cycle accurate. Further, theSingleStep debugger calls a MMK library function such as mmk-access toaccess memory. The MMK library function returns a value indicating howmany clock cycles the call took, and how successful it was.

[2394] For slow memory, the mmk-access function may either return thetotal number of clock cycles required, or it can return a smaller numberof clock cycles, such as 1. Further, it may indicate that the memoryaccess isn't over. SingleStep may then call mmk-access repeatedly untilthe memory access completes. The mmk-access function may also returnindicating that no clock cycles have passed. This can be used to allowthe SingleStep debugger to respond to user interaction and updatewindows. The MMK library may model just the memory logic external to theCPU. In the alternative, it may also include some of the MMU, the Cacheand the Bus Interface Unit if the user wishes to use their ownimplementation instead of the SingleStep implementation or if SingleStepdoesn't provide an implementation of these for a particular processor.

[2395] The MMK API provides call back functions enabling the MMK libraryto create windows and add menu items. The MMK Library may update datastructures and use call-backs to inform SingleStep when the interruptstatus has changed. This enables clock-cycle accurate simulation ofinterrupts.

[2396] Peripheral API

[2397] The Peripheral API enables the user to integrate their externallogic with SingleSteps' own memory implementation. SingleSteps' ownmemory implementation allows one to specify which types of memory arewhere in the memory map. Also included are details such as RAM/ROM/WOM,access speed, burst read capabilities, whether the memory should becached, and what mode the processor should be in to be able to accessthe data: user/supervisor, instruction fetch/data fetch.

[2398] The Peripheral API functions are only called betweeninstructions. The functions are told which clock cycles they have beencalled on, so clock cycle accurate synchronization is still possible.Not being able to stop SingleStep on arbitrary clock cycles would limitthe users interaction with the debugger. It seems unlikely that theSingleStep GUI may be responsive while a peripheral library is blocking,(given that the MMK API provides an explicit means to allow the GUI tobe responsive during long peripheral simulation and the Peripheral APIdoesn't).

[2399] The Peripheral API provides call back functions, enabling thePeripheral library to create windows. The Peripheral Library may updatedata structures to inform SingleStep that the status of interrupts haschanged. The library cannot indicate when the change occurred, sosimulation of mid-instruction interrupts may not be possible.

[2400] General Comparison

[2401] The Peripheral API is implemented using some C++ class interfaceapparently inspired by COM. It may be quite easy to use once a dummylibrary library has been implemented. The ease with which the PeripheralAPI allows one to combine SingleStep implemented memory with peripheralsmakes the Peripheral API good for prototyping and experimenting witharchitectures before one is committed to one. The MMK interface wouldrequire either changing the library code each time the memory modelchanged, or essentially a reimplementation of SingleSteps own memorymodel within a MMK library.

[2402] The MMK API is quite straight forward to use. It provides bothgeneric memory access routines and specialized ones. The user mayimplement at least one generic access function and any of thespecialized ones they wish. SingleStep may automatically decide whetherto use a generic or specialized access function. There are limits onwhere memory can sensibly be implemented. The SingleStep debugger needsto be able to access the contents of memory to updatewindows/disassemble machine code. If the implementation of the memoryisn't aware of the debuggers needs, the debuggers may not be able tobrowse memory contents. This makes implementing memory in anothersimulator undesirable.

Command Line Compiler

[2403] Environment Variables

[2404] The Handel-C compiler has three environment variables associatedwith it. HANDELC_SIM_COMPILE is an alternative to the -cI command lineoption. It is used to create the simulation file when compiling usingthe command line. HANDELC_LIBPATH is the search path for libraries. Thevalue of HANDELC CPPFLAGS is passed as command line options to thepreprocessor each time the compiler is executed.

[2405] The Handel-C installation sets the HANDELC_CPPFLAGS variable tocontain the -C option and to add the include directory to the searchpath for the preprocessor. The -C option passes source code commentsthrough to the compiler.

[2406] One is free to change the value of the HANDELC_CPPFLAGS and theHANDELC_LIBPATH to whatever he or she requires. To change theenvironment variables use the facilities described in the installationinstructions.

[2407] Temporarily Changing the Environment Variables

[2408] One can temporarily alter the value of the variable by typing thefollowing at the DOS prompt (Windows 98) or the command prompt (WindowsNT):

[2409] set HANDELC_CPPFLAGS=Command Line Options

[2410] For example:

[2411] set HANDELC_CPPFLAGS=C -include -DDEBUG.

[2412] Summary of Command Line options

[2413] This present section details all the command line options of theHandel-C compiler and stand-alone simulator. FIGS. 45A and 45B summarizethe options 4500 available on the compiler.

[2414] Target Options

[2415] The Handel-C compiler can target the simulator or hardware. Onlyone target option (-s, -vhdl or -edit) may be specified on the commandline.

[2416] Target Simulator

[2417] To target the simulator, use the -s option on the compilercommand line. handelc -s file.c To enable debugging, use the -g option.handelc -s -g file.c

[2418] Optimiser Options

[2419] The -O option enables all optimizations. For example, to compilethe program prog.c with all optimizations, one could type:

[2420] handelc -s -O prog.c

[2421] Enabling all optimizations may substantially add to compilationtime. If no optimizer command line options are specified then someoptimizations are disabled to reduce compilation times at the expense ofa few additional gates in the netlist.

[2422] Debugging Options

[2423] Various options are provided to aid with debugging Handel-Cprograms.

[2424] Turning on all Warnings

[2425] The -W option tells the compiler to display all warnings duringcompilation. By default, some less interesting warnings may be disabledand may not be displayed by the compiler.

[2426] Estimating Logic Area and Depth

[2427] The Handel-C compiler -e option gives feedback on logic usage anddepth to help with optimizing the Handel-C designs. The feedbackconsists of an HTML file for the project and an HTML file for eachsource file in the project. These highlight parts of the source codewith colors which relate to the logic depth and usage. These estimatesare provided as a guide only since full place and route is needed to getexact logic area and timing information. Nevertheless, they provide avaluable starting point for optimization. To generate an HTML file, usethe -e option. For example: handelc -e test.c

[2428] This may generate two files test.html (summarizing the project)and test_c.html (estimating logic usage) which can be loaded into a Webbrowser such as Internet Explorer or Netscape. The project file links tothe other html files of highlighted source code, and to the lines withthe highest area or delays. The source code estimation is in two parts:estimates of logic area and estimates of logic delay (i.e. logic depth).The code is colored from blue (low) through yellow to red (high) toindicate area or delay. Optimization should concentrate on red areasfirst.

[2429] Compilation Control Options

[2430] Two options are provided to control compilation.

[2431] Pass Options to Preprocessor

[2432] The -cpp option can be used to pass options to the preprocessor.For example, to add the directory include to the search path, one couldtype;

[2433] handelc -s -cpp -Iinclude prog.c

[2434] -I, -D and -U can be used directly and do not have to be passedto the preprocessor with -cpp . . . 13 Example programs.

[2435] Introduction

[2436] This section details the basic example programs supplied with theHandel-C compiler and describes how to compile and simulate them.

[2437] Basic Examples

[2438] Example 1 Simple accumulator example

[2439] Shows the use of file input and output in simulation.

[2440] Example 2 Pipelined multiplier example

[2441] Shows the use of a replicator.

[2442] Example 3 Queue example

[2443] Shows the use of multiple mains in different files and how totake advantage of this Handel-C feature to test programs.

[2444] Example 4 Clients/server example

[2445] Shows the use of prialt, mpram, arrays of functions and separateclocks.

[2446] Example 5 Preprocessor example

[2447] Builds a program which calculates Fibonacci numbers.

[2448] Example C: edge detector example

[2449] This is a series of programs showing how to port conventional Croutines to Handel-C. Each of the programs is in a separate projectwithin a single workspace.

[2450] Files Required for the Examples

[2451] The example project settings have been set up to reference thestandard macro library (stdlib.lib) and its associated header file. Ifone moves the project or use the files in a different project, he or shemay need to have the following project settings.

[2452] Preprocessor

[2453] Set the pathname handel-c rootpathname\include in the Additionalinclude directories pane Linker

[2454] Add stdlib.lib to the Object/library modules pane

[2455] Set the pathname handel-c root pathname\Lib in the Additionallibrary path.

[2456] Example 1: The Accumulator Example

[2457] This program takes a number of values from a file and calculatesthe sum of those values. It illustrates the basics of producing aHandel-C program and demonstrates the use of the simulator.

[2458] Compiling and Simulating the Program

[2459] Open the workspace file(HandelC\Examples\Handel-C\Example1\Example1.hw) by double-clicking onit. Handel-C may start with the Example1 workspace open. Check that fileview is the current view, and click on the +sign to the left of the chipicon to see what files are within the project. If one wishes to examinethe code, double-click the file sum.c in the workspace pane. If onecannot see it, he or she can make the workspace pane larger by draggingits border, or make the space allocated to filenames larger by draggingthe border of the Object button.

[2460] Build the project, by selecting Build Example1 from the Buildmenu. Messages from the compiler may appear in the output window. Theymay give an approximation of the number of hardware gates required toimplement the program.

[2461] One can then start the debugger and simulator by typing F11 (tostep through it) or F5 to run to the end. The simulator then startsimmediately and reads the contents of values from the file sum_in.dat,sums them, and writes the result to the file sum_out.dat. One can watchthe accumulation progressing in the variable sum by opening a Watchwindow (select View>Debug Windows>Watch or type Alt 3) and typing sum inthe window. The simulator may not terminate at the end of the program.To stop simulation, go to Debug>Stop Debugging. Examine the files toensure that the output file contains the correct result. If one wishesto change the values in sum_in, ensure that each value is placed on aline of its own.

[2462] Example 2: The Pipelined Multiplier Example

[2463] This program performs multiplication using a replicated parallelstructure to create a pipeline.

[2464] The operands used are the initialization values to the arrays ofleftOps and rightOps, such that the result[n]=leftOps[n] * rightOps[n].

[2465] This multiplier calculates the 16 LSBs of the result of a 16 bitby 16 bit multiply using long multiplication. The multiplier producesone result per clock cycle with a latency of 16 clock cycles. This meansthat although any one result takes 16 clock cycles, one gets athroughput of 1 multiply per clock cycle. Since each pipeline stage isvery simple, combinatorial logic is shallow and a much higher clock rateis achieved than would be possible with a complete single cyclemultiplier.

[2466] At each clock cycle, partial results pass through each stage ofthe multiplier in the sum array. Each stage adds on 2 n multiplied bythe b operand if required. The LSB of the a operand at each stage tellsthe multiply stage whether to add this value or not.

[2467] Operands are fed in on every clock cycle on signals leftOp andrightOp. Results appear 16 clock cycles later on every clock cycle onsignal result.

[2468] Code Details

[2469] /*

[2470] * Index at end of array macro

[2471] */

[2472] #define IndexAtArrayEnd(Index, ArrayLimit) \

[2473] select(exp2(width(Index)) =<=(ArrayLimit), !(Index), ((Index)=<=\

[2474] (ArrayLimit)))

[2475] The IndexAtArrayEnd macro tests if the index of size ArrayLimitis at the end of an array, whatever width the index counter has beenassigned by the compiler. In most cases, this is a normal comparison,but if the index overflows, the test may compare the overflow value. Anexample is an index of size 4. The compiler may assign the index a widthof 2 bits (to store the values 0-3). When it is compared against 4, itthe index may hold the value 0 (as the most significant bit has beenlost). In this case, the IndexAtArrayEnd macro compares against 0instead of against 4. This implies that such a comparison cannot be madeat the start of the cycle, when element zero is being processed, butonly at the end of the cycle after the index has been incremented.

[2476] Compiling and Simulating the Program

[2477] One can compile and simulate the program by opening the workspacein the examples\Handel-C\Example2 directory and selecting Build Example2from the Build menu. A person can then start the debugger.

[2478] Example 3: The Queue Example

[2479] The program is in three files: queue.c handles the queuefunction, while main.c provides I/O facilities. Definitions common toboth files are given in queue.h. They both have a clock set (in thiscase, the same clock source is used for both functions).

[2480] The queue function code illustrates the use of parallel tasks andchannel communications by implementing a simple four place queue. Eachtask holds one piece of data and has an input channel connected to theprevious queue location and an output channel connected to the nextqueue location.

[2481] At each iteration, the data moves one place up the queue. Theprogram executes an infinite loop, and one may use Stop Debugger toterminate the simulation.

[2482] Detailed Explanation

[2483] This example uses four parallel tasks each containing one word ofdata. At each iteration, one word is passed from one task to another ina chain. The links between the processes are entries in the links arrayof channels while the input and output to and from the system is handledby the main function.

[2484] Communication between the two functions is handled by an array ofchannels. The queue only reads data and writes data on every other clockcycle. A replicated pipeline is used to implement the queue. The firstand last entries in the pipeline are treated differently by using aselect statement to differentiate them at compile time. To watch thequeue in the debugger, start the debugger, and add the queue variablesto the watch window, (state etc.) If one adds an array name to the watchwindow, a + sign appears. Click on the + to get a list of the arrayelements.

[2485] Summary

[2486] This example has shown how to create parallel tasks and how tocommunicate between those tasks. It has also illustrated arrays ofvariables and arrays of channels. The example shows a project containingindependent main functions which are implemented independently inhardware.

[2487] Also, the queue presented here is parameterized on the width ofthe input and output channels because the width of all internalvariables are undefined and inferred by the compiler.

[2488] Running the Example

[2489] Double-click on the workspace file Example3.hw in theexamples\Handel-C\Example3 directory.

[2490] Compile and build it by selecting Build>Build Example3.

[2491] Step into the program within the debugger by pressing F11.

[2492] One may be asked to select a clock for the debugger to use. Inthis case they are both identical.

[2493] Select one and click OK.

[2494] View local variables by selecting View>Debug Windows>Variables(or press Alt 4) and select the Locals tab.

[2495] The variables local to the function may be visible in the Debugwindow.

[2496] One can watch the values change as he or she steps through thecode (repeatedly press F11).

[2497] Example 4: The Client/Server Example

[2498] The clients and server are implemented as independent pieces ofhardware, communicating via channels. The server reads data from anarray of channels from the client and puts the results in a queue asthey arrive. They are read from the queue by a dummy service routine.This is where the client requests could be processed by a real serverroutine. The server clock runs at half the speed of the client clock toallow time for complex assignments during request processing. There is apair of identical client functions. These functions merely select validrequests from an array and send them to the server.

[2499] Code Details

[2500] The internal queue is implemented in a structure consisting oftwo counters (queueIn and queueOut) which are used to test how full thequeue is, and an mpram containing the queued data. Use of an mpramallows the queue to be written to and read from in the same clock cycle.

[2501] typedef struct {

[2502] unsigned int queueIn;

[2503] unsigned int queueOut;

[2504] mpram

[2505] {

[2506] wom int DataWidth in[MaxQueue];

[2507] rom int DataWidth out[MaxQueue];

[2508] } values;

[2509] } Queue;

[2510] Running the Example

[2511] Double-click on the workspace file Example4.hw in theexamples\Handel-C\Example4 directory.

[2512] Compile and build it by selecting Build>Build Example4.

[2513] Step into the program within the debugger by pressing F11

[2514] Example 5: The Microprocessor Example

[2515] In this example, Handel-C implements a simple microprocessor.This microprocessor executes a program stored in ROM to calculatemembers of the Fibonacci number sequence.

[2516] Compiling and Simulating the Program

[2517] Compile and link the program by opening the workspace in theexamples\Handel-C\Example5 directory and then building the project.Simulate the program by starting the debugger (press F11 tosingle-step).

[2518] Detailed Explanation

[2519] The system described in this example consists of a ROM containingthe program to execute, a RAM containing some scratch variables and aprocessor that understands 10 opcodes. Each instruction is made up of a4 bit opcode and a 4 bit operand. The_asm_preprocessor macro is theassembler for this language and is used to fill in the entries in theprogram ROM declaration.

[2520] The processor has three registers:

[2521] a program counter, pc, that points to the next instruction to befetched from the ROM

[2522] an instruction register, ir, containing the instruction beingexecuted

[2523] an accumulator register, x, used as one input to the ‘ALU’

[2524] The instructions that the processor can execute are: OpcodeDescription HALT Stop processing LOAD Load a value from RAM into x LOADILoad a constant into x STORE Store x to RAM ADD Add a value from RAM tox SUB Subtract a value from RAM from x JUMP Unconditional jump to a ROMlocation JUMPNZ Jump to a ROM location if x is not 0 INPUT Read a valueinto x OUTPUT Write x to user

[2525] Using these instructions, a ROM is built containing a program togenerate the Fibonacci numbers. The execution unit of the processorsimply fetches instructions from the program ROM and executes them usinga switch statement. While it may appear to be a simple example it shouldbe easy to see how this example could be extended to implement a morecomplex processor. What has been produced is a processor which containsthe instructions necessary to calculate Fibonacci numbers. It is equallypossible to produce processors which contain specialized instructionsfor any application. Thus, one could use Handel-C to develop processorscapable of executing programs for specialized applications with theminimum of effort. FIGS. 46A and 46B illustrate various commands anddebugs 4600, in accordance with one embodiment of the present invention.

[2526]FIGS. 47A through 47C illustrate various icons 4700 that may beutilized, in accordance with one embodiment of the present invention.

[2527] Utilities

[2528] Introduction

[2529] The Handel-C compiler package also contains the followingutilities.

[2530] bmp2raw converts BMP image files to a format suitable for inputto the Handel-C simulator. raw2bmp generates BMP image files from a filegenerated by the Handel-C simulator.

[2531] The edge detector example requires an image as its source andgenerates an image as its results. The bmp2raw utility and its partnerraw2bmp are provided with the Handel-C compiler to perform conversionsbetween BMP image files and the file format suitable for the Handel-Csimulator. They are not restricted for use with the edge detectorexample and may be used for converting files for the image processingapplications.

[2532] These utilities can handle both raw binary and text file formats.This is useful if, as with the edge detector, a conventional C programrequires raw binary input and output whereas the simulator requires textinput and output. The raw data format can be configured to have thecolor bits in any order to allow simulation of applications requiringnon-standard bit patterns (e.g. 5-6-5 bit RGB format).

[2533] The bmp2raw Utility

[2534] The general usage of the bmp2raw utility is as follows:

[2535] bmp2raw [-b] BMPFile RAWFile RGBFile

[2536] Here BMPFile is the source image file, RAWFile is the destinationraw data file and RGBFile is a file describing the format of the pixelsin the raw data file.

[2537] Adding the -b flag as the first command line option causes theutility to generate a raw binary file rather than a text file. To seethe difference, consider a file containing the numbers 0 to 3. The textversion (no -b option) would look like this:

[2538] 0x00

[2539] 0x01

[2540] 0x02

[2541] 0x03

[2542] The binary version (created with -b option) would not be visiblewhen loaded into an editor. Instead, a hex dump of the file might looklike this: 00000000 01 02 03 ** ** ** ** . . . **** The format of theraw data file can be controlled with the RGBFile specified on thecommand line. This tells the utility where to place each color bit inthe words in the raw data file. Internally, the pixels in the BMP fileare expanded to 8 bits for each of red, green and blue. The RGBdescription file has the general format:

[2543] Red

[2544] Location for bit 7 of red

[2545] Location for bit 6 of red

[2546] Location for bit 5 of red

[2547] Location for bit 4 of red

[2548] Location for bit 3 of red

[2549] Location for bit 2 of red

[2550] Location for bit 1 of red

[2551] Location for bit 0 of red

[2552] Green

[2553] Location for bit 7 of green

[2554] Location for bit 6 of green

[2555] Location for bit 5 of green

[2556] Location for bit 4 of green

[2557] Location for bit 3 of green

[2558] Location for bit 2 of green

[2559] Location for bit 1 of green

[2560] Location for bit 0 of green

[2561] Blue

[2562] Location for bit 7 of blue

[2563] Location for bit 6 of blue

[2564] Location for bit 5 of blue

[2565] Location for bit 4 of blue

[2566] Location for bit 3 of blue

[2567] Location for bit 2 of blue

[2568] Location for bit 1 of blue

[2569] Location for bit 0 of blue

[2570] The file works by starting counting at bit 7 of the colorspecified by the identifier word and works down through the bits of thatcolor placing each bit in the specified location in the destinationword. The destination word may automatically be created wide enough tocontain the most significant bit specified (up to 32 bits wide intotal).

[2571] One need not specify 8 locations for each color The leastsignificant bits of each color may be dropped if fewer than 8 locationsare specified. In the example below, the least significant 6 bits of redand blue and the least significant 4 bits of green are dropped. FIG. 48illustrates the various raw file bit numbers and the corresponding colorbits 4800.

[2572] Such values use the following RGBFile:

[2573] Red

[2574] 7

[2575] 2

[2576] Green

[2577] 6

[2578] 3

[2579] 1

[2580] 0

[2581] Blue

[2582] 5

[2583] 4

[2584] Each pixel number and identifier (Red, Green or Blue) may appearon a separate line. One may also specify multiple identifiers of thesame color. The bit counter may continue to count down from the valuereached for that color each time one specifies the color again. Forexample, the above file could also be written as follows:

[2585] Red

[2586] 7

[2587] Green

[2588] 6

[2589] Blue

[2590] 5

[2591] Red

[2592] 2

[2593] Green

[2594] 3

[2595] 1

[2596] Blue

[2597] 4

[2598] Green

[2599] 0

[2600] RGBFile Example

[2601] There is an example file provided with the utilities to perform acommon conversion.

[2602] 8BPPdest.rgb Extracts red component from source image andgenerates 8 bit per pixel raw image. Useful for greyscale images

[2603] The raw2bmp Utility

[2604] The raw2bmp utility is the reverse of the bmp2raw utility. Itconverts raw text or binary files to BMP image files. The main use ofthe raw2bmp utility is to allow viewing of the output from imageprocessing applications with the standard Windows 98 or NT Paintutilities.

[2605] The general usage of the raw2bmp utility is as follows:

[2606] raw2bmp [-b] Width RAWFile BMPFile RGBFile.

[2607] Width the width of the image (the height may be calculated fromthis parameter and the source file length).

[2608] RAWFile source file containing raw data.

[2609] BMPFile destination image file.

[2610] RGBFile file describing the format of the pixels in the raw datafile.

[2611] Adding the -b flag as the first command line option causes theutility to read a raw binary file rather than a text file.

[2612] The format of the RGBFile describing where each bit is located inthe raw data word is similar to the file used by the bmp2raw utility.Indeed, for some pixel formats (including the example presented in theprevious section) a common file may be used. As an example of where adifferent file may be required, consider the conversion of 8 bit perpixel greyscale images to a BMP image. Here, each bit may be duplicatedin the red, green and blue components of the destination BMP file. Forexample:

[2613] red

[2614] 7

[2615] 6

[2616] 5

[2617] 4

[2618] 3

[2619] 2

[2620] 1

[2621] 0

[2622] green

[2623] 7

[2624] 6

[2625] 5

[2626] 4

[2627] 3

[2628] 2

[2629] 1

[2630] 0

[2631] blue

[2632] 7

[2633] 6

[2634] 5

[2635] 4

[2636] 3

[2637] 2

[2638] 1

[2639] 0

[2640] RGBFile Example

[2641] An example file is provided with the utility:

[2642] 8BPPsrc.rgb Duplicates each bit of 8 bit per pixel raw file tored, green and blue components. Useful for greyscale images.

[2643] Error Messages.

[2644] Introduction

[2645] Most error messages should be obvious. Some of the less obviousones may be due to system problems, such as files being corrupted,unavailable or in the wrong format, or the system riot having enoughdisk space to write to a file Error messages that do not fall into thesecategories are listed below with a brief explanation.

[2646] Handel-C Environment

[2647] “Handel-C cannot continue with Find in Files. Details:”

[2648] File could not be open or read

[2649] “Handel-C could not insert the project file in to the workspace.Details: ”

[2650] File could not be open or read

[2651] “Handel-C could not load the browse-info database file”

[2652] File could not be open or read

[2653] “Handel-C could not start the simulator. Details:”

[2654] File could not be open or read

[2655] “None of the simulator DLLs have any clocks defined.”

[2656] One has no main programs associated with clocks in the compiledcode.

[2657] “The simulator ‘NN’ does not have any clocks defined.”

[2658] One has built a function with no clock and attempted to simulateit. One should have a clocked main function that interfaces to theunclocked function.

[2659] “The symbol ‘NN’ is not defined.”

[2660] The cursor is not on a known symbol or a symbol has not beenselected in the file

[2661] “There is no browse information for the project NN.”

[2662] One did not have generate browse information selected when he orshe compiled the file

[2663] Compiler Error Messages

[2664] “Attempt to access partial struct/union ‘NN’”

[2665] Struct or union not fully defined. E.g.

[2666] struct S;

[2667] S x;

[2668] x.Bill;

[2669] without the definition.

[2670] struct S

[2671] {

[2672] int Bill;

[2673] “Cannot compile object—not all information is known”

[2674] Could not infer a width or type etc. E.g. int undefined x;

[2675] “Cannot target EDIF—not all information is known”

[2676] Could not infer a width or type etc. E.g. int undefined x;

[2677] “Cannot target RTL level VHDL—not all information is known”

[2678] Could not infer a width or type etc. E.g. int undefined x;

[2679] “Cannot target simulator—not all information is known”

[2680] Could not infer a width or type etc. E.g. int undefined x;

[2681] “Could not determine which clock to use for ‘%s’.

[2682] An object requiring a clock was built but the compiler couldn'twork out which clock it should be connected to. Probably caused by anunused object (the compiler finds clocks from an object's use and notits declaration).

[2683] “Could not infer information about this object”

[2684] Could not infer a width or type etc. E.g. int undefined x;

[2685] “Design contains an unbreakable combinational cycle”

[2686] Compiler could not break a combinatorial code loop.

[2687] “Error while compiling simulation output (%s)”

[2688] The back end simulation compiler (e.g. VC++) failed to compilethe simulation output. (E.g. not enough disk space, could not find file,illegal option specified in -cl, internal compiler error etc.).

[2689] “External tool not found (preprocessor or backend C compiler notin path)”

[2690] Error when the compile cannot run the C preprocessor or the Ccompiler used to compile the simulation .dll.

[2691] “Illegal use of identifier ‘%s’”

[2692] Probably caused by using a typedef name as a variable.

[2693] “Memory forms do not match”

[2694] Caused by comparing two types of memory (e.g. one is ram int x[1]and the other is rom int y[1]

[2695] “Syntax error”

[2696] Syntax error in source code

[2697] “Variable ‘%s’ is used from more than one clock domain”

[2698] Data may be passed to different clock domains using a channel oran interface. Variables cannot be shared between clock domains

[2699] Simulator Error Messages

[2700] Illegal Base Specification

[2701] base specification not 2, 8, 10 or 16

[2702] Invalid Input File

[2703] infile in wrong format

[2704] The simulator also forwards errors from plugins that have beenwritten using the API.

Handel-C Language

[2705] This section deals with some of the basics behind the Handel-Clanguage. Handel-C uses the syntax of conventional C with the additionof inherent parallelism. One can write sequential programs in Handel-C,but to gain maximum benefit in performance from the target hardware onemay use its parallel constructs. These may be new to some users.

[2706] If one is familiar with conventional C he or she may recognizenearly all the other features. Handel-C is designed to allow one toexpress the algorithm without worrying about how the underlyingcomputation engine works. This philosophy makes Handel-C a programminglanguage rather than a hardware description language. In some senses,Handel-C is to hardware what a conventional high-level language is tomicroprocessor assembly language.

[2707] It is important to note that the hardware design that Handel-Cproduces is generated directly from the source program. There is nointermediate ‘interpreting’ layer as exists in assembly language whentargeting general purpose microprocessors. The logic gates that make upthe final Handel-C circuit are the assembly instructions of the Handel-Csystem.

[2708] Handel-C Programs

[2709] Since Handel-C is based on the syntax of conventional C, programswritten in Handel-C are implicitly sequential. Writing one command afteranother indicates that those instructions should be executed in thatexact order.

[2710] Just like any other conventional language, Handel-C providesconstructs to control the flow of a program. For example, code can beexecuted conditionally depending on the value of some expression, or ablock of code can be repeated a number of times using a loop construct.

[2711] Parallel Programs

[2712] Because the target of the Handel-C compiler is low-levelhardware, massive performance benefits are made possible by the use ofparallelism. It is possible (and indeed essential for writing efficientprograms) to instruct the compiler to build hardware to executestatements in parallel. Handel-C parallelism is true parallelism—it isnot the time-sliced parallelism familiar from general purpose computers.

[2713] When instructed to execute two instructions in parallel, thosetwo instructions may be executed at exactly the same instant in time bytwo separate pieces of hardware.

[2714] When a parallel block is encountered, execution flow splits atthe start of the parallel block and each branch of the block executessimultaneously. Execution flow then rejoins at the end of the block whenall branches have completed. FIG. 49 illustrates the manner 4900 inwhich branches that complete early are forced to wait for the slowestbranch before continuing.

[2715]FIG. 49 illustrates the branching and re-joining of the executionflow. The left hand branch 4902 and middle branch 4904 may wait toensure that all branches have completed before the instruction followingthe parallel construct can be executed.

[2716] Channel Communications

[2717]FIG. 50 illustrates the link 5000 between parallel branches, inaccordance with one embodiment of the present invention. Channels 5001provide a link between parallel branches. One parallel branch 5002outputs data onto the channel and the other branch 5004 reads data fromthe channel. Channels also provide synchronization between parallelbranches because the data transfer can only complete when both partiesare ready for it. If the transmitter is not ready for the communicationthen the receiver may wait for it to become ready and vice versa.

[2718] Here, the channel is shown transferring data from the left branchto the right branch. If the left branch reaches point a before the rightbranch reaches point b, the left branch waits at point a until the rightbranch reaches point b.

[2719] Scope and Variable Sharing

[2720]FIG. 51 illustrates the scope 5100 of variables, in accordancewith one embodiment of the present invention. The scope of declarationsis, as in conventional C, based around code blocks. A code block isdenoted with {. . . } brackets. This means that:

[2721] Global variables may be declared outside all code blocks.

[2722] An identifier is in scope within a code block and any sub-blocksof that block.

[2723] Since parallel constructs are simply code blocks, variables canbe in scope in two parallel branches of code. This can lead to resourceconflicts if the variable is written to simultaneously by more than oneof the branches. Handel-C syntax states that a single variable may notbe written to by more than one parallel branch but may be read from byseveral parallel branches. This provides some powerful operations to bedescribed later.

[2724] If one wishes to write to the same variable from severalprocesses, the correct way to do so is by using channels which are readfrom in a single process. This process can use a prialt statement toselect which channel is ready to be read from first, and that channel isthe only one which may be allowed to write to the variable

[2725] while (1)

[2726]1prialt

[2727] {

[2728] case chan1? y:

[2729] break;

[2730] case chan2? y:

[2731] break;

[2732] case chan3? y:

[2733] break;

[2734] }

[2735] In this case, three separate processes can attempt to change thevalue of y by sending data down the channels, chan1, chan2 and chan3. ymay be changed by whichever process sends the data first. A singlevariable should not be written to by more than one parallel branch.

[2736] Alternate Embodiments

[2737] Introduction

[2738] This section summarizes the new features in Handel-C version 3for those familiar with previous versions. It also detailsincompatibilities between the current version and Handel-C version 2. 1.The following constructs have been added or changed. Terms specific toHandel-C have been given in bold. All other terms are fully compatiblewith ISO-C (ISO/IEC 9899:1999) unless otherwise stated. (ISO-C waspreviously known as ANSI-C.)

[2739] Operator Meaning ISO-C Change in Version 3

[2740]FIGS. 52, 53 and 54 illustrate a table of operators, statements,and macros respectively, along with alternate meanings thereof.

[2741] Linker Changes

[2742] Multiple files can be linked together and loaded into a singleFPGA. This allows one to create and access library files. One can load asingle chip with multiple main functions. This means that one can haveindependent logic blocks using different clocks running within the sameFPGA. The clock can be internal or external. External clocks may be userspecified.

[2743] Language Changes

[2744] ISO-C compatible extensions:

[2745] Compatibility with ISO standard C has been increased, so moststandard types and derived types are supported. This includes pointersand structures but does not include floats; goto, continue and returnare supported. (Note that one cannot use goto, continue or break toenter or exit from a par statement.) Handel-C now supports functions.These can be used instead of macros.

[2746] Functions can be immediately expanded using the inline keyword.To support the multiple files system, prototypes are supported, as arethe ISO-C keywords, extern and static. One can send messages to thestandard error channel using the assert directive.

[2747] Macro Changes

[2748] One can now declare local variables inside a macro expression.There is a new directive, ifselect, which permits conditionalcompilation according to the result of a test at compile time.

[2749] Statements

[2750] The Handel-C language has been extended to allow code to bereplicated using a construct similar to a for loop. This means that onecan generate multiple identical copies of the same block of code, eitherin sequence or in parallel.

[2751] Architecture

[2752] There is a new type to represent signals. One can havemulti-dimensional arrays of RAMs and dual-ported RAMs. Interfaces havebeen extended to allow one to connect to undefined input or outputports. One can also define the sorts of interface and use them to linkto blocks of external code (currently VHDL or EDIF). Interfacesdeclarations have changed, and the previous style is deprecated.

[2753] Pins no longer need to be assigned, One can omit the dataspecification to leave the pin assignment unconstrained. In this case,the place and route tools may assign the pins. A person can havemultiple clocks within a system, and refer to the current clock byusing_(——)clock.

[2754] Compiler Changes

[2755]FIG. 55 illustrates a system 5500 including a compiler 5501, inaccordance with one embodiment of the present invention. The newcompiler has a linker 5502, allowing one to have multiple input files5504 and links to library files. Multiple files can now be linked into asingle output module. These files can be pre-compiled core modules,libraries, header files, or pieces of VHDL code. The extern keywordallows one to reference a function or variable in another file.

[2756] Linking is carried out during a build.

[2757] Incompatibilities with Version 2.1

[2758] Symbol Scoping Rules

[2759] The rules for scoping for macro expr and macro proc constructshave changed between version 2.1 and 3.0. Version 2.1 expands macros inthe scope of their use. Version 3.0 expands macros in the scope of theirdeclaration. This is consistent with C scoping rules. For example:

[2760] int x; // Version 3.0 may use this x

[2761] macro expr a=x

[2762] void main(void)

[2763] int x; // Version 2.1 may use this x

[2764] y=a;

[2765] }

[2766] This may lead to undeclared identifier errors. For example, thefollowing code is valid in version 2.1 but not in version 3.0:

[2767] macro proc a(x)

[2768] {

[2769] b (x);

[2770] }

[2771] macro proc b(y)

[2772] Y++;

[2773] }

[2774] void main(void)

[2775] {

[2776] int 4 z;

[2777] a(z)

[2778] }

[2779] Using Macro Expressions in Widths

[2780] Version 3.0 requires disambiguating brackets around macroexpressions used in variable widths. For example:

[2781] int log2ceil(64) x;

[2782] may be rewritten as:

[2783] int (log2ceil(64)) x;

[2784] New Keywords Clashing with Variable Names

[2785] Version 3.0 contains a number of new keywords which may clashwith variable names in version 2.1 code.

[2786] The list of new keywords is:

[2787] assert auto const continue double enum extern float goto ifselectin inline let mpram register return seq signal sizeof static. Structtypedef typeof union volatile wom

[2788] Additional Combinational Loops

[2789] Version 2.1 uses approximations when checking for combinatorialloops in the generated logic. Version 3.0 does not use suchapproximations and may report unbreakable combinational loops inprograms which compile with version 2.1.

[2790] Clock is Required for Simulation

[2791] Version 3.0 requires that a clock is specified when generatingsimulation output. A dummy clock such as ‘set clock=external “P1”;’ isvalid.

Language Basics

[2792] Introduction

[2793] This section of the present description deals with the basics ofproducing Handel-C programs

[2794] Program Structure

[2795] Sequential Structure

[2796] As in a conventional C program, a Handel-C program consists of aseries of statements which execute sequentially. These statements arecontained within a main( ) function that tells the compiler where theprogram begins. The body of the main function may be split into a numberof blocks using {. . . } brackets to break the program into readablechunks and restrict the scope of variables and identifiers.

[2797] Handel-C also has functions, variables and expressions similar toconventional C. There are restrictions where operations are notappropriate to hardware implementation and extensions where hardwareimplementation allows additional functionality.

[2798] Parallel Structure

[2799] Unlike conventional C, Handel-C programs can also have statementsor functions that execute in parallel. This feature is crucial whentargeting hardware because parallelism is the main way to increaseperformance by using hardware. Parallel processes can communicate usingchannels. A channel is a one-way point-to-point link between twoprocesses.

[2800] Overall Structure

[2801] The overall program structure consists of one or more mainfunctions, each associated with a clock. One would only use more thanone main function if he or she needed parts of the program to run atdifferent speeds (and so use different clocks). A main function isdefined as follows:

[2802] Global Declarations

[2803] Clock Definition

[2804] void main(void)

[2805] {

[2806] Local Declarations

[2807] Body Code

[2808] }

[2809] The main( ) function takes no arguments and returns no value.This is in line with a hardware implementation where there are nocommand line arguments and no environment to return values to. The argc,argv and envp parameters and the return value familiar from conventionalC can be replaced with explicit communications with an external system(e.g. a host microprocessor) within the body of the program.

[2810] Using the Preprocessor

[2811] As with conventional C, the Handel-C source code is passedthrough a C preprocessor before compilation. Therefore, the usual#include and #define constructs may be used to perform textualmanipulation on the source code before compilation.

[2812] Handel-C also supports macros that are more powerful than thosehandled by the preprocessor.

[2813] Comments

[2814] Handel-C uses the standard /* . . . */ delimiters for comments.These comments may not be nested. For example:

[2815] /* Valid comment */

[2816] /* This is /* NOT */ valid */

[2817] Handel-C also provides the C++ style // comment marker whichtells the compiler to ignore everything up to the next newline. Forexample:

[2818] x=x+1; // This is a comment

[2819] Comments are handled by the preprocessor.

[2820] Declarations.

[2821] Introduction

[2822] This section of the present description details the types ofdeclarations that can be made and the way that the type system inHandel-C differs from that of conventional C.

[2823] Handel-C Values and Widths

[2824] A crucial difference between Handel-C and conventional C isHandel-C's ability to handle values of arbitrary width. Sinceconventional C is targeted at general purpose microprocessors it handles8, 16 and 32 bit values well but cannot easily handle other widths. Whentargeting hardware, there is no reason to be tied to these data widthsand so Handel-C has been extended to allow types of any number of bits.Handel-C has also been extended to cope with extracting bits from valuesand joining values together to form wider values. These operationsrequire no hardware and can provide great performance improvements oversoftware.

[2825] When writing programs in Handel-C, care should be taken that datapaths are no wider than necessary to minimize hardware usage. While itmay be valid to use 32-bit values for all items, a large amount ofunnecessary hardware is produced if none of these values exceed 4 bits.Care may also be taken that values do not overflow their width. This ismore of an issue with Handel-C than with conventional C becausevariables should be just wide enough to contain the largest valuerequired (and no wider).

[2826] Constants

[2827] Constants may be used in expressions. Decimal constants arewritten as simply the number while hexadecimal constants may be prefixedwith 0x or 0X, octal constants may be prefixed with a zero and binaryconstants may be prefixed with 0b or 0B. For example:

[2828] w=1234; /* Decimal */

[2829] x=0x1234; /* Hexadecimal */

[2830] y=01234; /* Octal */

[2831] z=0b00100110; /* Binary */

[2832] The width of a constant may be explicitly given by ‘casting’. Forexample:

[2833] x=(unsigned int 3) 1;

[2834] Casting may be necessary where the compiler is unable to inferthe width of the constant from its usage.

[2835] Types

[2836] Handel-C uses two kinds of objects: logic types and architecturetypes. The logic types specify variables. The architecture types specifyvariables that require a particular sort of hardware architecture (e.g.,ROMs, RAMs and channels). Both kinds are specified by their scope(static or extern), their size and their type. Architectural types arealso specified by the logic type that uses them.

[2837] Both types can be used in derived types (such as structures,arrays or functions) but there may be some restrictions on the use ofarchitectural types.

[2838] Specifiers

[2839] The type specifiers signed, unsigned and undefined define whetherthe variable is signed and whether it takes a default defined width. Onecan use the storage class specifiers extern and static to define thescope of any variable.

[2840] Functions can have the storage class inline to show that they areexpanded in line, rather than being shared.

[2841] Type Qualifiers

[2842] Handel-C supports the type qualifiers const and volatile toincrease compatibility with ISO-C. These can be used to further qualifylogic types.

[2843] Disambiguator

[2844] Handel-C supports the extension <>. This can be used to clarifycomplex declarations of architectural types.

[2845] Logic Types

[2846] The basic logic type is an int. It may be qualified as signed orunsigned. Integers can be manually assigned a width by the programmer orthe compiler may attempt to infer a width from use. Enumeration types(enums) allow one to define a specified set of values that a variable ofthis type may hold. There are derived types (types that are derived fromthe basic types). These are arrays, pointers, structs bit fields, andfunctions. The non-type void enables one to declare empty parameterlists or functions that do not return a value The typeof type operatorallows one to reference the type of a variable.

[2847] Int

[2848] There is only one fundamental type for variables: int. Bydefault, integers are signed. The int type may be qualified with theunsigned keyword to indicate that the variable only contains positiveintegers or 0. For example:

[2849] int 5 x;

[2850] unsigned int 13 y;

[2851] These two lines declare two variables: a 5-bit signed integer xand a 13-bit non-negative integer y. In the second example here, the intkeyword is optional. Thus, the following two declarations areequivalent.

[2852] unsigned int 6 x;

[2853] unsigned 6 x;

[2854] One may use the signed keyword to make it clear that the defaulttype is used. The following declarations are equivalent.

[2855] int 5 x;

[2856] signed int 5 x;

[2857] signed 5 x;

[2858] The range of an 8-bit signed integer is −128 to 127 while therange of an 8-bit unsigned integer is 0 to 255 inclusive. This isbecause signed integers use 2's complement representation. One maydeclare a number of variables of the same type and width simultaneously.For example:

[2859] int 17 x, y, z;

[2860] This declares three 17-bit wide signed integers x, y and z.

[2861] Supported Types for Porting

[2862] Handel-C provides support for porting from conventional C byallowing the types char, short and long. For example:

[2863] unsigned char w;

[2864] short y;

[2865] unsigned long z;

[2866] The widths assumed for each of these types is as follows: TypeWidth char  8 bits (signed) short 16 bits long 32 bits

[2867] Smaller and more efficient hardware may be produced by only usingvariables of the smallest possible width.

[2868] More About Widths

[2869] The Handel-C compiler can sometimes infer the width of variablesfrom their usage. It is therefore not always necessary to explicitlydefine the width of all variables and the undefined keyword can be usedto tell the compiler to try to infer the width of a variable. Forexample:

[2870] int 6 x;

[2871] int undefined y;

[2872] In this example the variable x has been declared to be 6 bitswide and the variable y has been declared with no explicit width. Thecompiler can infer that y may be 6 bits wide from the assignmentoperation later in the program and sets the width of y to this value. Ifthe compiler cannot infer all the undefined widths, it may generateerrors detailing which widths it could not infer. The undefined keywordis optional, so the two definitions below are equivalent:

[2873] int x;

[2874] int undefined x;

[2875] Handel-C provides an extension to allow one to override thisbehavior to ease porting from conventional C. This allows one to set awidth for all variables that have not been assigned a specific width ordeclared as undefined. This is done as follows:

[2876] set intwidth=16;

[2877] int x;

[2878] unsigned int y;.

[2879] This declares a 16-bit wide signed integer x and a 16-bit wideunsigned integer y. Any width may be used in the set intwidthinstruction, including undefined. One can still declare variables thatmay have their width inferred by using the undefined keyword. Forexample:

[2880] set intwidth=27;

[2881] unsigned x;

[2882] unsigned undefined y;

[2883] This example declares a variable x with a width of 27 bits and avariable y that has its width inferred by the compiler. This examplealso illustrates that the int keyword may be omitted when declaringunsigned integers. One may also set the default width to be undefined:

[2884] set intwidth=undefined;

[2885] Syntax

[2886] [signed|unsigned] int [undefined|n] Name

[2887] Arrays

[2888] One can declare arrays of variables in the same way that arraysare declared in conventional C. For example:

[2889] int 6x[7];

[2890] This declares 7 registers each of which is 6 bits wide. Accessingthe variables is exactly as in conventional C. For example, to accessthe fifth variable in the array:

[2891] x[4]=1;

[2892] Note that as in conventional C, the first variable has an indexof 0 and the last has an index of n−1 where n is the total number ofvariables in the array. One can also declare multi-dimensional arrays ofvariables. For example:

[2893] unsigned int 6 x[4] [5] [6];

[2894] This declares 4 * 5 * 6=120 variables each of which is 6 bitswide. Accessing the variables is as expected from conventional C. Forexample:

[2895] y=x[2] [3] [1];

[2896] Example

[2897] This loop initializes all the elements in array ax to the valueof index.

[2898] unsigned int 6 ax[7];

[2899] unsigned index;

[2900] index=0;

[2901] do

[2902] {

[2903] ax[index]=(0@ index);

[2904] index++;

[2905] }

[2906] while(index<=6);

[2907] Note that the width of index has to be adjusted in theassignment. This is because its width may be inferred to be 3, from thearray dimension (the array has 7 elements, so “index” may only ever needto count as far as 6).

[2908] Enum

[2909] enum specifies a list of constant integer values, e.g. enumweekdays {MON, TUES, WED, THURS, FRI}; The first name (in this case MON)has a value of 0, the next 1, and so on, unless explicit values arespecified. If not all values are specified, values increment from thelast specified value. To specify enum values enum weekdays {MON=9, TUES,WED, THURS, FRI}; In the beta release, one cannot declare a variable oftype enum,(for example, enum weekdays x; is not allowed). One can assignenum values to a variable (e.g. int x=MON;)

[2910] struct

[2911] struct defines a data structure; a grouping together of variablesunder a single name. The format of the structure can be identified by atype name. The variable members of the structure may be of the same ordifferent types. Once a structure has been declared, its type name canbe used to define other structures of the same type. Structure membersmay be accessed individually using the construct struct_Name.member Name

[2912] Syntax

[2913] A structure type is declared using the format

[2914] struct [type_Name]

[2915] {

[2916] member-list

[2917] }[instance_Names];

[2918] member-list is a list of variable definitions terminated bysemi-colons The use of instance_Names declares variables of thatstructure type. Alternatively, one may declare variables as follows:

[2919] struct type_Name instance_Name;

[2920] Storage

[2921] Structures may be passed through channels and signals. Structuresmay be stored in internal memory elements. Structures cannot be storedin offchip rams. If a structure contains a memory element, a channel, ora signal, it cannot be stored in another memory element, it cannot bepassed to a function “by value”, it cannot be assigned to and it cannotbe passed through a channel or a signal. If a structure contains amemory element with more than one member, it cannot be assigned (orassigned to) another structure as the assignment cannot be performed ina single clock cycle. Whole structures may not be sent directly tointerfaces.

[2922] Example

[2923] struct human // Declare human struct type

[2924] {

[2925] unsigned int 8 age; // Declare member types

[2926] int 1 sex;

[2927] char name[25];

[2928] }; // Define human type

[2929] struct human sister;

[2930] sister.age=25;

[2931] Bit Field

[2932] A bit field is a type of structure member consisting of aspecified number of bits. The length of each field is separated from thefield name by a colon (:). Each element can be accessed independently.Since Handel-C allows one to specify the width of integers in bits, abit field is merely another way of specifying a standard structure. InISO-C, bit fields are made up of words, and only the specified bits areaccessed, the rest are padded. Padding in ISO-C is implementationdependent. Nothing can be assumed about padding in Handel-C.

[2933] Syntax

[2934] struct

[2935] {

[2936] field_Type field_Name: field_width

[2937] . . .

[2938] }

[2939] Example

[2940] This example defines an array of flags named flags as a structureand as a bit field

[2941] struct structure

[2942] {

[2943] unsigned int 1 LED;

[2944] unsigned int 1 signal;

[2945] unsigned int 1 switch;

[2946] }outputs;

[2947] struct bitfield

[2948] {

[2949] unsigned int LED : 1;

[2950] unsigned int signal : 1;

[2951] unsigned int switch : 1;

[2952] }signals;

[2953] union united

[2954] {

[2955] unsigned char chis[2];

[2956] unsigned short shis;

[2957] };

[2958] union united unity;

[2959] unsigned a;

[2960] par

[2961] }

[2962] unity.chis[0]=2;

[2963] unity.chis[1]=50;

[2964] }

[2965] unity.shis=33;.

[2966] Pointers and Addresses

[2967] Pointers in Handel-C are similar to those in conventional C. Theyprovide the address of a variable or a piece of code. This enables oneto access variables by reference rather than by value. The indirectionoperator * is the same as it is in ISO-C. It is used to declare pointersto objects, and to de-reference pointers (i.e. to access objects pointedto by pointers).

[2968] The “address of” operator (&) works as it does in ISO-C (althoughtechnically Handel-C variables are not usually stored in memorylocations that need to be addressed).

[2969] Pointers

[2970] A pointer declaration consists of the indirection operator (*),the name of the pointer and the type of the variable that it points to.type *Name They are used to point to variables in conjunction with theunary operator &, which gives the address of an object. To set a pointerto point to a variable, one may assign the address of the variable tothe pointer. For example:

[2971] int 8 *ptr; //declare a pointer to an int 8

[2972] int 8 object, x;

[2973] object=6;

[2974] x=10;

[2975] ptr=&object //assigns the address of

[2976] // object to pointer

[2977] x=*pointer // x is now 6

[2978] *pointer=12; //object is now 12

[2979] In Handel-C, one may only cast null pointers (void * pointerName)to a different type. All other pointers may only be cast to change thesign of an object pointed to, and whether it is const or volatile. Theserestrictions are the standard casting restrictions in Handel-C. One canchange a null pointer's type by casting, assignment or comparison.

[2980] Valid pointer operations include:

[2981] Assign a pointer to another pointer of the same type

[2982] Add or subtract a pointer and an integer

[2983] Subtract or compare a pointer to an array member with anotherpointer to a member of the same array

[2984] Assign or compare a pointer to NULL.

[2985] Pointers to Functions

[2986] If one points to code (a function), the address operator is notrequired. The syntax is return Type (*pointer.Name)(parameter list) Theparentheses at the end of the declaration declare the pointer to be thepointer to a function. The indirection operator before the pointerNamedeclares it to be a pointer declaration. There is the standard C typeambiguity between the declaration of a function returning a pointer anda pointer to a function. To ensure that indirection operator isassociated with the pointer name rather than the return type, one needsto use parentheses int 8 * functionName( ); //function returning pointerand int 8 (* pointerName)( ); //pointer to function

[2987] operator/& operator

[2988] The indirection operator * is the same as it is in ISO C. It isused to declare pointers to objects, and to de-reference pointers (i.e.to access objects pointed to by pointers). The address operator (&)works as it does in ISO-C (although technically Handel-C variables arenot usually stored in memory locations that need to be addressed).

[2989] unsigned char cha, chb, *chp;

[2990] chp=&cha;

[2991] cha=90;

[2992] chb=*chp;

[2993] chp=&chb;

[2994] The first line declares two unsigned variables (cha and chb), anda pointer to an unsigned (chp). The second line assigns the address ofcha to pointer chp. In other words, pointer chp now points to variablecha. The third line simply assigns a value to cha. The fourth linedereferences pointer chp, to access what it's pointing to, which is cha.In other words, chb is assigned the value of the object pointed to bychp. The last line assigns the address of chb to pointer chp. In otherwords, pointer chp now points to variable chb. The following can also beused: pointers to arrays, pointers to channels, pointers to signals,pointers to memory elements, pointers to structures and unions, pointersto pointers, arrays of pointers. For instance:.

[2995] struct S

[2996] {

[2997] int 6 a, b;

[2998] } s1, s2, * sp, **spp;

[2999] sp=&s1;

[3000] spp=&sp;

[3001]2 ** spp;

[3002] This declares two variables of type struct S (s1 and s2 ), apointer to a variable of this type (sp), and a pointer to a pointer to avariable of this type (spp). The next line assigns the address ofstructure s1 to pointer sp (pointer sp to point to structure s1). Thefollowing line assigns the address of pointer sp to pointer spp (pointerspp to point to pointer sp). The last line dereferences pointer spptwice, and it assigns the dereferenced value, which is s1, to structures2 (i.e. s2 now equals s1).

[3003] Structure Pointers

[3004] The structure pointer operator (->) can be used, as in ISO-C. Itis used to access the members of a structure or union, when thestructure/union is referenced through a pointer.

[3005] struct S

[3006] {

[3007] int 18 a, b;

[3008] } s, *sp;

[3009] sp=&s;

[3010] s.a 26;

[3011] sp->b=sp->a;

[3012] The last line accesses the member variables of structure sthrough pointer sp. Because the pointer is being used to access thestructure, the ->operator is used to refer to the member variables.

[3013] sp->a ≡(*sp).q

[3014] One can cast structure pointers between structures with the samemember types. For example:

[3015] struct S1

[3016] {

[3017] int 6 x;

[3018] }

[3019] struct S2

[3020] {

[3021] int 6 y;

[3022] }

[3023] struct S1 *strctptr=&S 1;

[3024] S2. y=(struct S2 *)strctPtr->y.

[3025] Architectural Types

[3026] The architectural types are channels (used to communicate betweenparallel processes), interfaces (used to connect to pins or providesignals to communicate with external code), memories (rom, ram, wom andmpram) and signal (declares a wire). The disambiguator < > has beenprovided to help clarify the definitions of memories, channels andsignals.

[3027] Channels

[3028] Handel-C provides channels for communicating between parallelbranches of code. One branch writes to a channel and a second branchreads from it. The communication only occurs when both tasks are readyfor the transfer at which point one item of data is transferred betweenthe two branches. Channels are declared with the chan keyword. Forexample:

[3029] chan int 7 link;

[3030] As with variables, the Handel-C compiler can infer the width of achannel from its usage if it is declared with the undefined keyword.Channels can also be declared with no explicit type. The compiler infersthe type and width of the channel from its usage. For example:

[3031] set intwidth=undefined;

[3032] chan int Link1;

[3033] chan unsigned undefined Link2;

[3034] chan Link3;

[3035] Syntax

[3036] chan [logicType] Name

[3037] Arrays of Channels

[3038] Handel-C allows arrays of channels to be declared. For example:

[3039] chan unsigned int 5 x[6];

[3040] This is equivalent to declaring 6 channels each of which is 5bits wide. A channel can be accessed by specifying its index. As withvariable arrays, the index for the nth element is n−1. For example:

[3041] x[4] ! 3; // Output 3 on channel x[4]

[3042] x[3] ? y; // Input to y from channel x[3]

[3043] It is also possible to declare multi-dimensional arrays ofchannels. For example:.

[3044] chan unsigned int 6 x[4][5][6];

[3045] This declares 4 * 5 * 6=120 channels each of which is 6 bitswide. Accessing the channels is similar to accessing arrays inconventional C. For example:

[3046] x[2][3][1]! 4; // Output 4 on channel

[3047] Interfaces

[3048] One may use an interface to communicate with an external deviceor component. An interface consists of data ports, together withinformation about each port. A port definition consists of the data typethat uses it (either defined or inferred from its first use), anoptional name and the specification for that port (e.g., input pins fora bus) if needed.

[3049] Targeting Hardware

[3050] The different varieties of interfaces are known as sorts.Handel-C provides predefined sorts (bus_in bus_latch_in, bus_clock_in,bus_out, bus_ts, bus _ts latch_in, bus_ts_clock_in, port_in andport_out. The Handel-C bus sorts (bus_*) generate the hardware for busesconnected to pins. The port in and port_out sorts generate the hardwarefor floating ports (buses which are not connected to pins). These can beof any width, and can carry signals between different sections ofHandel-C code, or to software or hardware beyond the Handel-C program.One may also define the interface to connect to non-Handel-C objects:Native PC object code used in simulation. Programs that run on the PCfor simulation and connect to a Handel-C interface are known as plugins.There are special port specifications to enable one to connectuser-defined interfaces with a plugin for simulation. These are extlib,extfunc, extpath and extinst. Hardware descriptions written in anotherlanguage. Currently only VHDL and EDIF are supported. For a VHDL codeinterface, the interface sort would be the name of the VHDL entity.

[3051] The style of interface declaration used in Handel-C Version 2 isdeprecated, but remains for backward compatibility. The recommendedstyle is to declare an interface sort and then to define instances ofthat sort. The interface declaration gives the port names and types butno further details about them. The interface definition gives the port.specifications (if needed) and assigns data to be transmitted to theoutput ports.

[3052] Interface Declaration

[3053] interface Sort({data_TO_hc})

[3054] ({send_FROM_hc})

[3055] Sort may be a user-defined name or one of the pre-defined sorts(bus_in, bus latch_in, bus_clock_in, bus_out, bus_ts, bus_ts_latch_in,bus_ts_clock_in, port_in and port_out). data_TO_hc is optional. Itconsists of one or more prototypes of ports bringing data TO theHandel-C code from the outside world. A port prototype consists of theport type, and the port name send_FROM_hc is optional. It consists ofone or more definitions of ports carrying data FROM the Handel-C code tothe outside world (port definition as above). At least one port (whetherto Handel-C or from Handel-C) may be declared.

[3056] Interface Definition

[3057] interface Sort({port_TO hc_[with {portSpec}]})

[3058] Name({port_FROM_hc=outputDataItem

[3059] [with {portSpec}]})

[3060] with {generalSpecs};

[3061] Sort is a pre-declared interface sort (as above).

[3062] port_TO_hc consists of definitions of the ports bringing data toHandel-C that were prototyped in the interface declaration. These portsmay have the type given in the prototype, but may also have portspecifications. The most likely use of a port specification is if onewere interfacing with an external DLL (dynamic linked library) andneeded to specify the external function that this port required(extfunc). Name is a user-defined identifier for that instance of theinterface port_FROM_hc consists of definitions of ports sending datafrom the Handel-C code that were prototyped in the sort declaration.These ports may have the type given in the prototype, but may also haveport specifications. Each port_FROM_hc port should be assigned anexpression outputDataItem. The value of outputDataItem may be sent tothat port.

[3063] with {generalspecs} is optional. It consists of one or more portspecifications that apply to all the ports within the interface. Onemight wish to specify the external simulator that handles this type ofport (generates input and receives output) using the extlib directive.

[3064]FIG. 56 illustrates the various specifications 5600 for theinterfaces of the present invention.

[3065] Note that ports to the code precede the interface Name and portsfrom it follow it.

[3066] Example

[3067] Further examples of bus interfaces are given later. The presentexample shows an interface declaration used to connect to a piece offoreign code, and the definition that uses this declaration.

[3068] // Interface declaration

[3069] interface ttl7446 (unsigned 7 segments, unsigned 1 rbon)

[3070] (unsigned 1 ltn, unsigned 1 rbin, unsigned 4 digit,

[3071] unsigned 1 bin);

[3072] // Interface definition

[3073] interface ttl7446 (unsigned 7 segments, unsigned 1 rbon)

[3074] decode(unsigned 1 ltn=ltnVal, unsigned 1 rbin=rbinVal,

[3075] unsigned 4 digit=digitVal, unsigned 1 bin=binVal)

[3076] with {extlib=“PluginModelSim.dll”,

[3077] extinst=“decode; model=ttl7446_wrapper; delay=1”};.

[3078] Internal RAMs and ROMs

[3079] RAMs and ROMs may be built from the logic provided in the FPGAusing the ram and rom keywords. For example:

[3080] ram int 6 a[43];

[3081] rom int 16 b[4];={23, 46, 69, 92};

[3082] This example constructs a RAM consisting of 43 entries each ofwhich is 6 bits wide and a ROM consisting of 4 entries each of which is16 bits wide.

[3083] To initialize a static or global ROM, one can use the format

[3084] rom int 16 b[4]={23, 46, 69, 92};

[3085] The ROM is initialized with the constants given in the followinglist in much the same way as an array would be initialized in C. In thisexample, the ROM entries are given the following values: ROM entry Valueb[0] 23 b[l] 46 b[2] 69 b[3] 92

[3086] The Handel-C compiler can also infer the widths, types and thenumber of entries in RAMs and ROMs from their usage. Thus, it is notalways necessary to explicitly declare these attributes. For example:

[3087] ram int undefined a[123];

[3088] ram int 6 b[ ];

[3089] ram c[43];

[3090] ram d[ ];

[3091] RAMs and ROMs are accessed in much the same way as arrays. Forexample:

[3092] ram int 6 b[561;

[3093] b[7]=4;

[3094] This sets the eighth entry of the RAM to the value 4 Note that asin conventional C, the first entry in the memory has an index of 0 andthe last has an index of n−1 where n is the total number of entries inthe memory.

[3095] Note that RAMs differ from arrays in that an array is equivalentto declaring a number of variables. Each entry in an array may be usedexactly like an individual variable with as many reads and writes in aclock cycle as required. RAMs, however, are normally more efficient toimplement in terms of hardware resources than arrays. Therefore, oneshould use an array when he or she wishes to access the elements morethan once in parallel and he or she should use a RAM when he or sheneeds efficiency. Accessing internal RAMs can only be done in the waydescribed above on Altera or Xilinx devices with synchronous on-chipRAMs. This includes Altera Flex 10K and APEX, Xilinx 4000E, 4000EX,4000L, 4000XL, 400OXV, Spartan, Spartan II and Virtex 10K seriesdevices. Other memories may require timing specifications.

[3096] RAMs and ROMs may only have one entry accessed in any clockcycle. This restriction is discussed in more detail later.

[3097] Multidimensional Arrays

[3098] It is possible to create simple multi-dimensional arrays ofmemory using the ram, rom and wom keywords. The definitions can be madeclearer by using the optional disambiguator < >.

[3099] Syntax

[3100] ram|rom|worn logicType entry_width Name {[const_expression]}

[3101] [={initialisation strings}];

[3102] Possible logic types are ints, structs, pointers and arrays. Thelast constant expression is the index for the RAM. The other indicesgive the number of copies of that type of RAM.

[3103] Example

[3104] ram<int 6>a[15] [43];

[3105] rom<int 16>b [4] [2] [2]=

[3106] { {{1, 2},

[3107] {3, 4}

[3108] }

[3109] {{5, 6},

[3110] {7, 8}

[3111] },

[3112] {{9, 10},

[3113] {11, 12}

[3114] },

[3115] {{13, 14},

[3116] {15, 16}

[3117] }

[3118] };

[3119] This example constructs 15 RAMs, each consisting of 43 entries of6 bits wide and 4 * 2 ROMs, each consisting of 2 entries of 16 bitswide. The ROM is initialized with the constants in the following list inthe same way as a multidimensional array would be initialized in C. Thelast index (that of the RAM entry) changes fastest. FIG. 57 illustratesa table 5700 showing the ROM entries, in accordance with one embodimentof the present invention.

[3120] Because of their architecture, RAMs and ROMs are restricted toperforming operations sequentially. Only one element of a RAM or ROM maybe addressed in any given clock cycle and, as a result, familiar lookingstatements are often disallowed. For example:

[3121] ram <unsigned int S>x[4];

[3122] x[1]=x[3]+1;

[3123] This code is illegal because the assignment attempts to read fromthe third element of x in the same cycle as it writes to the firstelement. In a multi-dimensional array, one can access separate elementsof the arrays, so long as he or she is not accessing the same RAM (thepenultimate array index). For example:

[3124] x[2][1]=x[3][1] is valid

[3125] x[2][1]=x[2][0] is invalid

[3126] Note that arrays of variables do not have these restrictions butmay require substantially more hardware to implement than RAMs dependingon the target architecture.

[3127] mpram (multi-ported RAMs)

[3128] One can create multiple-ported RAMs (MPRAMs) by constructingsomething like an ISO-C union. One may use the mpram keyword. mprams canbe used to connect two independent code blocks. The clock of the mpramport is taken from the function in which it is used. The normaldeclaration of a MPRAM would be to create a dual-ported RAM by declaringtwo ports of equal width: for Altera, one port would be read-only andone write-only, for Xilinx 4000 one port would be read/write and oneread-only and for Virtex, both ports would be read/write.

[3129] Syntax

[3130] mpram MPRAM_name

[3131] {

[3132] ram_Type variable_Type RAM_Name [width];

[3133] ram_Type variable_Type RAM_Name [width];

[3134] Example

[3135] Using an mpram to communicate between two independent logicblocks:

[3136] File 1:

[3137] mpram Fred

[3138] {

[3139] ram <unsigned 8>ReadWrite[256]; // Read/write port

[3140] rom <unsigned 8>Read[256]; // Read only port

[3141] };

[3142] mpram Fred Joan; /*Declare Joan as an mpram like Fred */

[3143] set clock=internal “F8M”

[3144] void main(void)

[3145] {

[3146] unsigned 8 data;

[3147] Joan.ReadWrite[7]=data;

[3148] }

[3149] File 2:

[3150] mpram Fred

[3151] ram<unsigned 8>ReadWrite[256]; // Read/write port

[3152] rom<unsigned 8>Read[256]; // Read only port

[3153] };

[3154] extern mpram Fred Joan;

[3155] set clock=external “P2”

[3156] void main(void)

[3157] {

[3158] unsigned 8 data;

[3159] data=Joan.Read[7];

[3160] Mapping of Different Width Ports

[3161] If the ports of the mpram are of different widths, they may bemapped onto each other according to the specifications of the chip aperson is using. If the ports used are of different widths, the widthsshould have values of 2 n. Different width ports are not available withAltera devices.

[3162] Xilinx Bit Mapping

[3163] To find the bits that an array element occupies in a XilinxVirtex or 4000 series RAM, one can use the formula RAM array ram yName[a] may have a start bit of ((y+1) * a)−1 and an end bit of y*a .Xilinx mapping is little-endian. This means that the address points tothe LSB. The bits between the declarations of RAM are mapped directlyacross, so that bit 27 in one declaration may have the same value as bit27 in another declaration, even though the bits may be in differentarray elements in the different declarations.

[3164] mpram Joan

[3165] {

[3166] ram <unsigned 4>Readwrite[256]; // Read/write port

[3167] rom <unsigned 8>Read[256]; // Read only port

[3168] };

[3169] Joan.ReadWrite[100] may run from 400 to 403.

[3170] Joan.Read[100] may run from 800 to 807.

[3171] Joan-Read[50] may run from 400 to 407.

[3172] Joan.ReadWrite[100] is equivalent to Joan.Read[50] [0:3]

[3173] Initialisation of Mprams

[3174] The first member of the mpram can be initialized.

[3175] mpram Fred

[3176] {

[3177] ram <unsigned 8>ReadWrite[256]; // Read/write port

[3178] rom <unsigned 8>Read[256]; // Read only port

[3179] }Mary={10,11,12,13};

[3180] This would have the effect

[3181] Fred.ReadWrite[0]=10 Fred.ReadWrite[1]=1 1

[3182] Fred.ReadWrite[2]=12 Fred.ReadWrite[3]=13

[3183] The other elements of Fred.ReadWrite may not be initialized. Inthis case, since Fred.Read is the same size as Fred.ReadWrite, elements0-3 of Fred.Read would be initialized with the same values.

[3184] wom (write-only memory)

[3185] One can declare a write-only memory using the keyword worm. Theonly use of a write-only memory would be to declare an element within amulti-ported RAM. Since woms only exist inside multi-port rams, it isillegal to declare one outside a mpram declaration.

[3186] Syntax

[3187] wom variable_Type variable_Size WOM_Name[width]=initialise_Values[with {specs}]

[3188] Example

[3189] mpram connect

[3190] {

[3191] wom <unsigned 8>Writeonly[256]; // Write only port

[3192] rom <unsigned 8>Read[256]; // Read only port

[3193] };

[3194] Signal

[3195]FIG. 57A illustrates a method 5740 for using a dynamic object,i.e. signal, in a programming language. In general, in operation 5742,an object, i.e. signal, is defined with an associated first value andsecond value. The first value is then used in association with theobject during a predetermined clock cycle. See operation 5744. Thesecond value is used in association with the object before or after thepredetermined clock cycle, as indicated in operation 5746.

[3196] In an aspect of the present invention, the object may be used tosplit up an expression into sub-expressions. As an option, thesub-expressions may be reused. In another aspect, the first value may beassigned to and read from the object during the predetermined clockcycle. More information regarding the above concept will now be setforth in greater detail.

[3197] A signal is an object that takes on the value assigned to it butonly for that clock cycle. The value assigned to it can be read backduring the same clock cycle. At all other times it takes on itsinitialisation value. The default initialisation value is 0. Theoptional disambiguator < > can be used to clarify complex signaldefinitions.

[3198] Syntax

[3199] signal [<type data-width>] signal_Name;

[3200] Example

[3201] int 15 a, b;

[3202] signal <int>sig;

[3203] a=7;

[3204] par

[3205] {

[3206] sig=a;

[3207] b=sig;

[3208] }

[3209] sig is assigned to and read from in the same clock cycle, so b isassigned the value of a. Since the signal only holds the value assignedto it for a single clock cycle, if it is read from just before or justafter it is assigned to, one gets its initial value. For example:

[3210] int 15 a, b;

[3211] static signal <Ant>sig=690;

[3212] a=7;

[3213] par

[3214] {

[3215] sig=a;

[3216] b=sig;

[3217] }

[3218] a=sig;

[3219] Here, b is assigned the value of a through the signal, as before.Since there is a clock tick before the last line, a is finally assignedthe signal's initial value of 690.

[3220] Using Signals to Split Up Complex Expressions

[3221] One can split up complex expressions. E.g., b=(((a *2)−55)<<2)+100; could also be written

[3222] int 17 a, b;

[3223] signal s1, s2, s3, s4;

[3224] par

[3225] {

[3226] s1=a;

[3227] s2=s1 * 2;

[3228] s3=s2−55;

[3229] s4=s3<<2;

[3230] b=s4=100;

[3231] }

[3232] Breaking up expressions also enables one to re-usesub-expressions:

[3233] unsigned 15 a, b;

[3234] signal sig1;

[3235] par

[3236] {

[3237] sig1=x+2;

[3238] a=sig1* 3;

[3239] b=sig1/2;

[3240] Type Qualifiers

[3241] Handel-C supports the type-qualifiers const and volatile toincrease compatibility with ISO-C. These can be used to further qualifylogic types.

[3242] Const

[3243] const defines a variable or an array of variables that cannot beassigned to. This means that they keep the initialisation valuethroughout. They may be initialized in the declaration statement. Theconst keyword can be used instead of #define to declare constant values.It can also be used to define function parameters which are nevermodified. The compiler may perform type-checking on const variables andprevent the programmer from modifying it.

[3244] Example

[3245] const int i=5;

[3246] i=10; // Error

[3247] i++; // Error

[3248] volatile

[3249] In ISO-C, volatile is used to declare a variable that can bemodified by something other than the program. It is mostly used forhard-wired registers volatile controls optimization by forcing a re-readof the variable. It is only a guide, and may be ignored. The initialvalue of volatile variables is undefined. Handel-C does nothing withvolatile. It is accepted for compatibility purposes.

[3250] Complex Declarations

[3251] It is possible to have extremely complex declarations inHandel-C. One can combine arrays of functions, structs, arrays, andpointers with architectural types. To clarify such expressions, it iswise to use typedef.

[3252] Macro Expressions in widths

[3253] If one uses a macro expression to provide the width in a typedeclaration, one may enclose it in parentheses. This ensures that it maybe correctly parsed as a macro.

[3254] int (mac(x)) y;

[3255] To declare a pointer to a function returning that type, one gets:

[3256] int (mac(x) (*f)( );

[3257] (type clarifier)

[3258] < > is a Handel-C extension used to disambiguate complexdeclarations of architectural types. One cannot use it on logic types.It is good practice to use it whenever a person declares channels,memories or signals, to clarify the format of data passed or stored inthese variables.

[3259] Example

[3260] struct fishtank

[3261] {

[3262] int 4 koi;

[3263] int 8 carp;

[3264] int 2 guppy;

[3265] } bowl;

[3266] signal <struct fishtank>drip;

[3267] chan <int 8 (*runwater)()>tap;

[3268] It is required to disambiguate a declaration such as:

[3269] chan int *x //pointer to channel or

[3270] //channel of pointers?

[3271] This should be declared as

[3272] chan <int *>x //channel of pointers

[3273] or

[3274] chan <int>*x //pointer to channel.

[3275] Storage Class Specifiers

[3276] Storage class specifiers define how variables are accessed. Forcompatibility with ISO-C, the specifiers auto and register can be usedbut have no effect. The scope of a variable is declared by thespecifiers extern and static. The expansion of a function is defined bythe specifier inline. The typedef specifier allows one to declare newnames for existing types.

[3277] Auto

[3278] auto defines a local automatic variable. In Handel-C, all localvariables default to auto. One cannot initialize an auto variable, butmay assign it a value. The initialisation status of auto variables isundefined.

[3279] Example

[3280] auto pig;

[3281] pig=15;

[3282] extern

[3283] extern declares a variable that can be accessed by name from anyfunction. Extern variables may be defined once outside all functions.(By default, any variable declared outside a function is assumed to beextern.)

[3284] If the variable is used in multiple source files, it is goodpractice to collect all the extern declarations in a header file,included at the top of each source file using the #includeheaderFileName directive. Note that one cannot access the same variablefrom different clock domains.

[3285] Example

[3286] extern int 16 global_fish;

[3287] int global_frog=1234;

[3288] main( )

[3289] {

[3290] global_fish=global_frog;

[3291] . . .

[3292] }

[3293] Syntax

[3294] extern variable declaration;

[3295] functionName(parameter-type-list)

[3296] inline

[3297] inline causes a function to be expanded where it is called. Thelogic may be generated every time it is invoked. This ensures that thefunction is not accessed at the same time by parallel branches of code.By default, functions are assumed to be shared (not inline).

[3298] Example

[3299] inline int4 knit(int needle, int stitch)

[3300] {

[3301] needle=needle+stitch;

[3302] return(needle);

[3303] }

[3304] int 4 jumper[100];

[3305] par(needle=1; needle <100; needle=needle+2)

[3306] {

[3307] jumper[needle]=knit(needle, 1);

[3308] }

[3309] Syntax

[3310] inline function_Declaration;

[3311] register

[3312] register has been implemented for reasons of compatibility withISO-C. register defines a variable that has local scope. Its initialvalue is undefined.

[3313] Example

[3314] register int 16 fish;

[3315] fish=f(plop);

[3316] static

[3317] static gives a variable static storage (its values are kept atall times). This ensures that the value of a variable is preservedacross function calls. It also affects the scope of a variable or afunction. Static functions and static variables declared outsidefunctions can only be used in the file in which they appear. staticvariables declared within an inline function or an array of functionscan only be used in the copy of the function in which they appear.static variables are the only local variables (excluding consts) thatcan be initialized.

[3318] Example

[3319] static int 16 local_function (int water, int weed)

[3320] static int 16 local_fish=1234;

[3321] main( )

[3322] {

[3323] int fresh, pondweed;

[3324] local_fish=local_function(fresh, pondweed);

[3325] . . .

[3326] }

[3327] Syntax

[3328] static variable declaration;

[3329] staticfunctionName(parameter-type-list)

[3330] typedef

[3331] typedef defines another name for a variable type. This allows oneto clarify the code. The new name is a synonym for the variable type.

[3332] typedef int 4 SMALL_FISH;

[3333] If the typedef is used in multiple source files, it is goodpractice to collect all the type definitions in a header file, includedat the top of each source file using the #include headerFileNamedirective. It is conventional to differentiate typedef names fromstandard variable names, so that they are easily recognizable.

[3334] Example

[3335] typedef int 4 SMALL_FISH;

[3336] extern SMALL_FISH_stickleback;

[3337] typeof

[3338] The typeof type operator allows the type of an object to bedetermined at compile time. The argument to typeof may be an expression.Using typeof ensures that related variables maintain their relationship.It makes it easy to modify code by simplifying the process of sortingout type and width conflicts. A typeof-construct can be used anywhere atype name could be used. For example, one can use it in a declaration,in casts or inside typeof.

[3339] Syntax

[3340] typeof (expression)

[3341] Example

[3342] unsigned 9 ch;

[3343] typeof(ch @ ch) q;

[3344] struct

[3345] {

[3346] typeof(ch) cha, chb;

[3347] } si;

[3348] typeof(s1) s2;

[3349] ch=s1.cha+s2.chb;

[3350] q=s1.chb@ s2.cha;

[3351] If the width of variable ch were changed in this example, therewould be no need to modify any other code. This is also useful forpassing parameters to macro procs. The code below shows how to use atypeof definition to deal with multiple parameter types.

[3352] macro proc swap (a, b)

[3353] {

[3354] typeof(a) t;

[3355] t=a;

[3356] a=b;

[3357] b=t;

[3358] Variable Initialization

[3359] Global variables (i.e. those declared outside all code blocks)may be initialized with their declaration. For example:

[3360] int 15 x=1234;

[3361] Variables declared within functions can only be initialized ifthey have static storage or are consts. All other variables may not beinitialized this way. Instead, one may use an explicit sequential orparallel list of assignments following the declarations to achieve thesame effect. For example:

[3362] {

[3363] int4x;

[3364] unsigned 5 y;

[3365] x=5;

[3366] y=4;

[3367] }

[3368] Global and static variables may only be initialized withconstants.

Statement

[3369] Introduction

[3370] As with conventional C, the execution flow of a Handel-C programis expressed as a series of statements such as assignment, conditionalexecution and iteration. Handel-C includes most of the statements fromconventional C and these arc detailed below.

[3371] Sequential and Parallel Execution

[3372]FIG. 57A-1 illustrates a method 5730 for using extensions toexecute commands in parallel. In general, in operation 5732, a pluralityof commands to be executed in parallel are designated.

[3373] This designation is replicated in operation 5734, and thecommands are executed in parallel recursively. Note operation 5736. Inone aspect, the commands may be executed in parallel recursivelyutilizing a FOR loop.

[3374] As an option, a first command may be executed simultaneously witha second command. Further, the first command may be executedsimultaneously with the second command in a single clock cycle.

[3375] Handel-C implicitly executes instructions sequentially but whentargeting hardware it is extremely important to make as much use aspossible of parallelism. For this reason, Handel-C also has a parallelcomposition keyword par to allow statements in a block to be executed inparallel.

[3376] The following example executes three assignments sequentially:

[3377] x=1;

[3378] y=2;

[3379] z=3;

[3380] in contrast, the following example executes all three assignmentsin parallel and in the same clock cycle:

[3381] par

[3382] {

[3383] x=1;

[3384] y=2;

[3385] }

[3386] z=3;

[3387] It should be noted that the second example executes allassignments literally in parallel. This is not the time-sliced pseudoparallelism of a conventional microprocessor implementation but threespecific pieces of hardware built to perform these three assignments.Detailed timing analysis may be dealt later, but for now it is enough tostate that the first example executes in 3 clock cycles while the secondgenerates a similar quantity of hardware but executes in 1 clock cycle.Therefore, it is obvious that parallelism is a very important constructfor targeting hardware. Within parallel blocks of code, sequentialbranches can be added by using a code block denoted with the {. . . }brackets instead of a single statement. For example:

[3388] par

[3389] {

[3390] x=1;

[3391] {

[3392] y=2;

[3393] z=3;

[3394] }

[3395] }

[3396] In this example, the first branch of the parallel statementexecutes the assignment to x while the second branch sequentiallyexecutes the assignments to y and z. The assignments to x and y occur inthe same clock cycle, the assignment to z occurs in the next clockcycle. The instruction following the par {. . . } may not be executeduntil all branches of the parallel block complete.

[3397] Seq

[3398] To allow replication, the seq keyword exists. Sequentialstatements can be written with or without the keyword. The followingexample executes three assignments sequentially:

[3399] x=1;

[3400] y=2;

[3401]2=3;

[3402] as does this:

[3403] seq

[3404] {

[3405] x=1;

[3406] y=2;

[3407] z=3

[3408] }

[3409] Replicated par and seq

[3410] One can replicate par and seq blocks by using a counted loop (asimilar construct to a for loop). The count is defined with a startpoint (index_Base below), an end point (index_Limit) and a step size(index_Count). The body of the loop is replicated as many times as thereare steps between the start and end points. If it is a par loop, thereplicated processes may run in parallel, if a seq, they may runsequentially.

[3411] Syntax par|seq (index_Base; index_Limit; index_Count) {. Body }index_Base, index_Limit and index_Count are macro exprs that areimplicitly declared. They do not need to be single expressions, forexample, one could declare par (i=0, j=23; i != 76; i++, j−−).

[3412] Example

[3413] par (i=0; i<3; i++)

[3414] {

[3415] a[i]=b[i];

[3416] }

[3417] expands to:

[3418] par

[3419] {

[3420] a[0]=b[0];

[3421] a[1]=b[1];

[3422] a[2]=b[2];

[3423] }

[3424] Replicated pipeline

[3425] unsigned init;

[3426] unsigned q[149];

[3427] unsigned 31 out;

[3428] init=57;

[3429] par (r=0;r<16;r++)

[3430] {

[3431] ifselect(r==0)

[3432] q[r]=init;

[3433] else ifselect(r==15)

[3434] out q[r−1];

[3435] else

[3436] q[r]=q[r−1];

[3437] }

[3438] ifselect checks for the start of the pipeline, the replicatorrules create the middle sections and ifselect checks the end. This codeexpands to:

[3439] par

[3440] {

[3441] q[0]=init;

[3442] q[1]=q[0];

[3443] q[2]=q[ ];

[3444] etc . . .

[3445] q[14]=q[13];

[3446] out q[14];

[3447] Assert

[3448] assert allows one to generate messages at compile-time if acondition is met. They can be used to check compile-time constants andhelp guard against possible problematic code alterations. The user usesan expression to check the value of a compile-time constant, and if theexpression evaluates to false, an error message is sent to the standarderror channel in the format

[3449] filename:(line number):(column number)::Assertion failed:user-defined

[3450] error string

[3451] Syntax

[3452] assert(condition, [string with format specification(s),{argument(s)}]); If condition is false, string may be sent to thestandard error channel, with each format specification replaced by anargument. When assert encounters the first format specification (ifany), it converts the value of the first argument into that format andoutputs it. The second argument is formatted according to the secondformat specification and so on. If there are more expressions thanformat specifications, the extra expressions are ignored. The resultsare undefined if there are not enough arguments for all the formatspecifications.

[3453] The format specification is one of:

[3454] %c Display as a character %s Display as a string

[3455] %d Display as a decimal %f Display as a floating point

[3456] % Display as an octal %x Display as a hexadecimal

[3457] Example:

[3458] int f(int x)

[3459] {

[3460] assert(width(x)==3, “Width of x is not 3 (it is %d)”,

[3461] width(x));

[3462] return x+1;

[3463] }

[3464] void main(void)

[3465] {

[3466] int 4 y;

[3467] y=f(y);

[3468] }

[3469] x may be inferred to have a width of 4, so the following messagemay be displayed. F:\proj\test.c(4)(2) : Assertion failed : Width of xis not 3 (it is 4).

[3470] Continue

[3471] continue moves straight to the next iteration of a for, while ordo loop. For do or while, this means that the test is executedimmediately. In a for statement, the increment step is executed. Thisallows one to avoid deeply nested if . . . else statements within loops

[3472] Example

[3473] for (i=100; i>0; i−−)

[3474] {

[3475] x=f(i);

[3476] if (x=1)

[3477] continue;

[3478] y+=*x;

[3479] }

[3480] One cannot use continue to jump out of or into par blocks

[3481] Goto

[3482] goto label moves straight to the statement specified by label,label has the same format as a variable name, and may be in the samefunction as the goto. Labels have function scope. Formally, goto isnever necessary. It may be useful for extracting from deeply nestedlevels of code in case of error.

[3483] Example

[3484] for( . . . )

[3485] {

[3486] for( . . . )

[3487] }

[3488] if(disaster)

[3489] goto Error;

[3490] {

[3491] }

[3492] Error:

[3493] output ! error_code;

[3494] One cannot use goto to jump out of or into par blocks

[3495] return [expression]

[3496] The return statement is used to return from a function to itscaller. return terminates the function and returns control to thecalling function. Execution resumes at the line immediately followingthe function call. return can return a value to the calling function.The value returned is of the type declared in the function declaration.Functions that do not return a value should be declared to be of typevoid.

[3497] Example

[3498] int power(int base, int n)

[3499] {

[3500] int i, p;

[3501] p=1;

[3502] for (i=1;i<=n,++i)

[3503] p=p *base;

[3504] return(p);

[3505] }

[3506] One cannot use return to jump out of par blocks

[3507] Assignments

[3508] Handel-C assignments are of the form:

[3509] Variable=Expression;

[3510] For example:

[3511] x=3;

[3512] y=a+b;

[3513] The expression on the right hand side may be of the same widthand type (signed or unsigned) as the variable on the left hand side. Thecompiler generates an error if this is not the case. The left hand sideof the assignment may be any variable, array element or RAM element. Theright hand side of the assignment may be any expression described later.Handel-C also provides a number of short cut assignment statements. Notethat these cannot be used in expressions as they can in conventional Cbut only in stand-alone statements. These short cuts are:

[3514] Statement Expansion

[3515] Variable++; Variable=Variable+1;

[3516] Variable−−; Variable=Variable −1;

[3517] ++Variable; Variable=Variable+1;

[3518] −−Variable; Variable=Variable−1;

[3519] Variable+=Expression; Variable=Variable+Expression;

[3520] Variable Expression; Variable=Variable−Expression;

[3521] Variable−=Expression; Variable=Variable−Expression;

[3522] Variable−=Expression; Variable=Variable|Expression;

[3523] Variable %=Expression; Variable=Variable % Expression;

[3524] Variable<<=Expression; Variable=Variable<<Expression;

[3525] Variable >>=Expression; Variable=Variable>>Expression;

[3526] Variable &=Expression; Variable=Variable & Expression;

[3527] Variable|=Expression; Variable=Variable|Expression;

[3528] Variable ^ =Expression; Variable=Variable ^ Expression;

[3529] Channel Communication

[3530] Channels are a way of communicating between processes. When onewrites to a channel, a copy of the data he or she writes is sent to thereceiving process. This allows information to be shared betweenprocesses. Since a variable cannot be written to by multiple processes,one can write to the variable in a single process by reading channelsthat send data from other processes. Each channel may be written to atone end, and read from at the other. The width and type of data sentdown the channel may be the same of the width and type of the channel.The channel can be an entry in an array of channels, or be pointed to bya channel pointer.

[3531] As with other variables, if no width or type is given to achannel, (or if it is set as undefined), the compiler can infer thechannel width and type from its use. Reading from a channel is done asfollows:

[3532] Channel? Variable;

[3533] This assigns the value read from the channel to the variable. Thevariable may also be a signal, an array element, RAM element or WOMelement.

[3534] Writing to a channel is as follows:

[3535] Channel ! Expression;

[3536] This writes the value of the expression to the channel.Expression may be any expression described later. No two statements maysimultaneously write to or simultaneously read from a single channel.

[3537] par

[3538] {

[3539] out !3 // Parallel write to a channel

[3540] out ! 4

[3541] }

[3542] This code is illegal as it attempts to write simultaneously to asingle channel. Similarly, the following code is illegal because anattempt is made to read simultaneously from the same channel:

[3543] par

[3544] {

[3545] in ? x; \\Parallel read from a channel

[3546] in ? y;

[3547] }

[3548] Example

[3549] set clock=external;

[3550] void main(void)

[3551] {

[3552] signal Fred;

[3553] unsigned 8 Res;

[3554] chan Bill;

[3555] par

[3556] {

[3557] Bill ! 23;

[3558] Bill ? Fred;

[3559] Res=Fred;

[3560] }

[3561] }

[3562] prialt

[3563] The prialt statement selects the first channel ready tocommunicate. The syntax is similar to a conventional C switch statement.

[3564] prialt

[3565] {

[3566] case CommsStatement:

[3567] Statement

[3568] break;

[3569] . . .

[3570] case CommsStatement:

[3571] Statement

[3572] break;

[3573] default:

[3574] Statement

[3575] break;

[3576] }.

[3577] prialt selects between the communications on several channelsdepending on the readiness of the other end of the channel.

[3578] CommsStatement may be one of the following:

[3579] Channel ? Variable

[3580] Channel ! Expression

[3581] The case whose communication statement is the first to be readyto transfer data may execute and data may be transferred over thechannel. The statements up to the next break statement may then beexecuted. The prialt construct does not allow the same channel to belisted twice in its cases and fall through of cases is prohibited. Thismeans that each case may have its own break statement. If two channelsare ready simultaneously, then the first one listed in the code takespriority.

[3582] Default

[3583] prialt with no default case:

[3584] execution halts until one of the channels becomes ready tocommunicate.

[3585] prialt statement with default case:

[3586] if none of the channels is ready to communicate immediately thenthe default branch statements executes and the prialt statementterminates.

[3587] Conditional execution (if . . . else)

[3588] Handel-C provides the standard C conditional execution constructas follows:

[3589] if(Expression)

[3590] Statement

[3591] else

[3592] Statement

[3593] As in conventional C, the else portion may be omitted if notrequired. For example:

[3594] if (x==1)

[3595] x=x+1;

[3596] Here, and throughout the rest of the present description,Statement may be replaced with a block of statements by enclosing theblock in {. . . } brackets. For example:

[3597] if (x>y)

[3598] {

[3599] a=b;

[3600] c=d;

[3601] }

[3602] else

[3603] {

[3604] a=d

[3605] c=b;

[3606] }

[3607] The first branch of the conditional is executed if the expressionis true and the second branch is executed if the expression is false.Handel-C treats zero values as false and non-zero values as true. As maybe seen later, the relational logical operators return values to matchthis meaning but it is also possible to use variables as conditions. Forexample:

[3608] if (x)

[3609] a=b;

[3610] else

[3611] c=d;

[3612] This is expanded by the compiler to:

[3613] if (x !=0)

[3614] a=b;

[3615] else

[3616] c=d;

[3617] When executed, if x is not equal to 0 then b is assigned to a. Ifx is 0 then d is assigned to c.

[3618] while loops

[3619] Handel-C provides while loops exactly as in conventional C:

[3620] while (Expression)

[3621] Statement

[3622] The contents of the while loop may be executed zero or more timesdepending on the value of Expression. While Expression is true thenStatement is executed repeatedly. Again, Statement may be replaced witha block of statements. For example:

[3623] x=0;

[3624] while (x!=45)

[3625] {

[3626] y=y+5;

[3627] x=x+1;

[3628] }

[3629] This code adds 5 to y 45 times (equivalent to adding 225 to y).

[3630] do . . . while loops

[3631] Handel-C provides do . . . while loops exactly as in conventionalC:

[3632] Do

[3633] Statement

[3634] while (Expression);

[3635] The contents of the do . . . while loop is executed at least oncebecause the conditional expression is evaluated at the end of the looprather than at the beginning as is the case with while loops. Again,Statement may be replaced with a block of statements. For example:

[3636] do

[3637] {

[3638] a=a+b;

[3639] x=x−1;

[3640] }while (x>y);

[3641] for loops

[3642] Handel-C provides for loops similar to those in conventional C.

[3643] for (Initialisation ; Test ; Iteration)

[3644] Statement

[3645] The body of the for loop may be executed zero or more timesaccording to the results of the condition test. There is a directcorrespondence between for loops and while loops.

[3646] for (Init; Test; Inc)

[3647] Body;

[3648] Is directly equivalent to:

[3649] {

[3650] Init;

[3651] while (Test)

[3652] {

[3653] Body;

[3654] Inc;

[3655] }

[3656] }

[3657] unless the Body includes a continue statement. In a for loopcontinue jumps to before the increment, in a while loop continue jumpsto after the increment. Each of the initialisation, test and iterationstatements is optional and may be omitted if not required. As with allother Handel-C constructs, Statement may be replaced with a block ofstatements. For example:

[3658] for ( ; x >y ; x++)

[3659] a=b;

[3660] c=d;

[3661] The difference between a conventional C for loop and the Handel-Cversion is in the initialisation and iteration phases. In conventionalC, these two fields contain expressions and by using expression sideeffects (such as++and −−) and the sequential operator ‘,’ conventional Callows complex operations to be performed. Since Handel-C does not allowside effects in expressions the initialisation and iteration expressionshave been replaced with statements. For example:

[3662] for (x=0; x<20; x=x+1)

[3663] {

[3664] y=y+2;

[3665] }

[3666] Here, the assignment of 0 to x and adding one to x are bothstatements and not expressions. These initialisation and iterationstatements can be replaced with blocks of statements by enclosing theblock in {. . . } brackets. For example:

[3667] for ( {x=0; y=23;} ; x<20; {x+=1; x*=2;} )

[3668] {

[3669] y=y+2;

[3670] }

[3671] switch

[3672] Handel-C provides switch statements similar to those inconventional C.

[3673] switch (Expression)

[3674] {

[3675] case Constant:

[3676] Statement

[3677] break;

[3678] . . .

[3679] default:

[3680] Statement

[3681] break;

[3682] }

[3683] The switch expression is evaluated and checked against each ofthe case compile time constants. The statement(s) guarded by thematching constant is executed until a break statement is encountered. Ifno matches are found, the default statement is executed. If no defaultoption is provided, no statements are executed.

[3684] Each of the Statement lines above may be replaced with a block ofstatements by enclosing the block in {. . . } brackets. As withconventional C, it is possible to make execution drop through casebranches by omitting a break statement. For example:

[3685] switch (x)

[3686] {

[3687] case 10:

[3688] a=b;

[3689] case 11:

[3690] c=d;

[3691] break;

[3692] case 12:

[3693] e=f.

[3694] break;

[3695] }

[3696] Here, if x is 10, b is assigned to a and d is assigned to c, if xis 11, d is assigned to c and if x is 12, f is assigned to e.

[3697] The values following each case branch may be compile timeconstants.

[3698] Break

[3699] Handel-C provides the normal C breaks statement both forterminating loops and separation of case branches in switch and prialtstatements.

[3700] When used within a while, do . . . while or for loop, the loop isterminated and execution continues from the statement following theloop. For example:

[3701] for (x=0; x<32; x++)

[3702] {

[3703] if (a[x]==0)

[3704] break;

[3705] b[x]=a[x];

[3706] }

[3707] // Execution continues here

[3708] When used within a switch statement, execution of the case branchterminates and the statement following the switch is executed. Forexample:

[3709] switch (x)

[3710] {

[3711] case 1:

[3712] case 2:

[3713] Y++;

[3714] break;

[3715] case 3:

[3716] z++;

[3717] break;

[3718] }

[3719] // Execution continues here

[3720] When used within a prialt statement, execution of the case branchterminates and the statement following the prialt is executed. Forexample:

[3721] prialt

[3722] {

[3723] case a ? x: x++;

[3724] break;

[3725] case b ! y:

[3726] break;

[3727] }

[3728] // Execution continues here

[3729] Example

[3730] int power(int base, int n)

[3731] {

[3732] int i, p;

[3733] p=1;

[3734] for (i 1; i<=n; ++i)

[3735] p=p *base;

[3736] return(p);

[3737] }

[3738] One cannot use return to jump out of par blocks

[3739] Delay

[3740] Handel-C provides a delay statement not found in conventional Cwhich does nothing but takes one clock cycle to do it. This may beuseful to avoid resource conflicts (for example to prevent two accessesto one RAM in a single clock cycle) or to adjust execution timing. Delaycan also be used to break combinatorial logic cycles.

[3741] Address and Indirection

[3742] The address operator (&) is used to access the address of avariable. The indirection operator * is the same as it is in ISO-C. Itis used to declare pointers to objects, and to de-reference pointers(i.e. to access objects pointed to by pointers).

[3743] Member Operators

[3744] The structure member operator (.) is used to access members of astructure or mpram, or to access a port within an interface. Thestructure pointer operator (->) can be used, as in ISO-C. It is used toaccess the members of a structure or mpram, when the structure/mpram isreferenced through a pointer.

[3745] mpram Fred

[3746] {

[3747] ram <unsigned 8>ReadWrite[256]; // Read/write port

[3748] rom <unsigned 8>Read[256]; // Read only port

[3749] } Joan;

[3750] mpram Fred *mpramPtr;

[3751] mpramPtr=&Joan;

[3752] x=mpramPtr->Read[56];

[3753] If a memory is made up of structures, the structure memberoperator can be used to reference structure members within the memory.

[3754] ram struct S compRAM[100];

[3755] ram struct S (*ramStructPtr)[ ];

[3756] ramStructPtr=&compRAM;

[3757] x=(*ramStructPtr)[10].a;.

Expressions

[3758] Introduction

[3759] Expressions in Handel-C take no clock cycles to be evaluated, andso have no bearing on the number of clock cycles a given program takesto execute. They do affect the maximum possible clock rate for a programthe more complex an expression, the more hardware is involved in itsevaluation and the longer it is likely to take because of combinatorialdelays in the hardware. The clock period for the entire hardware programis limited by the longest such evaluation in the whole program. Moredetails on timing and efficiency considerations will be set forthhereinafter in greater detail. Because expressions are not allowed totake any clock cycles, expressions with side effects are not permittedin Handel-C. For example;

[3760] a=b++; /* NOT PERMITTED */

[3761] This is not permitted because the ++ operator has the side effectof assigning b+1 to b which requires one clock cycle. Note that even thelongest and most complex C expression with many -side effects can bewritten in terms of a larger number of simpler expressions. Theresulting code is normally easier to read. For example:

[3762] a=(b++)+(((c−−? d++: e−−)), f);

[3763] can be rewritten as:

[3764] a=b+f;

[3765] b=b+1;

[3766] if (c)

[3767] d=d+1.

[3768] else

[3769] e=e−1;

[3770] c=c−1;

[3771] Note that Handel-C provides the prefix and postfix++ and−−operations as statements rather than expressions. For example:

[3772] a++;

[3773] b−−;

[3774] ++c;

[3775] −−d;

[3776] This example is directly equivalent to:

[3777] a=a+1;

[3778] b=b−1;

[3779] c=c+1;

[3780] d=d−1;.

[3781] Restrictions on RAMs and ROMs

[3782] Because of their architecture, RAMs and ROMs are restricted toperforming operations sequentially. Only one element of a RAM or ROM maybe addressed in any given clock cycle and, as a result, familiar lookingstatements are often disallowed. For example:

[3783] ram unsigned int 8 x[4];

[3784] x[1]=x[3]+1;

[3785] This code is illegal because the assignment attempts to read fromthe third element of x in the same cycle as it writes to the firstelement. Note that the ports within a multi-port RAM are in the sameelements of memory so one can only make a single access to any one mpramport in a single clock cycle. The following code is also disallowed:

[3786] ram unsigned int 8 x[4];

[3787] if (x[0]=0)

[3788] x[1]=1;

[3789] This is because the condition evaluation may read from element 0of the RAM in the same clock cycle as the assignment writes to element1. Similar restrictions apply to while loops, do . . . while loops, forloops and switch statements. Note that arrays of variables do not havethese restrictions but may require substantially more hardware toimplement than RAMs depending on the target architecture.

[3790] Operators

[3791] Bit Manipulation Operators

[3792] The following bit manipulation operators are provided inHandel-C: Operator Meaning << Shift left >> Shift right <− Take leastsignificant bits \\ Drop least significant bits @ Concatenate bits [ ]Bit selection

[3793] width(Expression) Width of expression

[3794] Shift Operators

[3795] The shift operators shift a value left or right by a variablenumber of bits resulting in a value of the same width as the value beingshifted. Any bits shifted outside this width are lost. When shiftingunsigned values, the right shift pads the upper bits with zeros. Whenright shifting signed values, the upper bits are copies of the top bitof the original value. Thus, a shift right by 1 divides the value by 2and preserves the sign. For example:

[3796] unsigned int 8 x;

[3797] int 8 y;

[3798] x=192;

[3799] y=−8;

[3800] y=x>>1;

[3801] y=y>>1;

[3802] This results in x being set to 96 and y being set to −4.

[3803] Take Operator

[3804] The take operator, <-, returns the n least significant bits of avalue. The drop operator, \\, returns all but the n least significantbits of a value. n may be a compile-time constant. For example:

[3805] macro expr four=8/2;

[3806] unsigned int 8 x;

[3807] unsigned int 4 y;

[3808] unsigned int 4 z;

[3809] x=0xC7;

[3810] y=x<-four;

[3811] z=x\\4;

[3812] This results in y being set to 7 and z being set to 12 (or 0xC inhexadecimal).

[3813] Concatenation Operator

[3814] The concatenation operator, @, joins two sets of bits togetherinto a result whose width is the sum of the widths of the two operands.For example:

[3815] unsigned int 8 x;

[3816] unsigned int 4 y;

[3817] unsigned int 4 z;

[3818] y=0xC;

[3819] z=0x7;

[3820] x=y @ z;

[3821] This results in x being set to 0xC7. The left operand of theconcatenation operator forms the most significant bits of the result.

[3822] Bit Selection

[3823] Individual bits or a range of bits may be selected from a valueby using the [ ] operator. Bit 0 is the least significant bit and bitn-1 is the most significant bit where n is the width of the value.

[3824] For example:

[3825] unsigned int 8 x;

[3826] unsigned int 1 y;

[3827] unsigned int 5 z;

[3828] x=0b01001001;

[3829] y=x[4];

[3830] z=x[7:3];

[3831] This results in y being set to 0 and z being set to 9. Note thatthe range of bits is of the form MSB:LSB and is inclusive. Thus, therange 7:3 is 5 bits wide.

[3832] Bit selection in RAM, ROM and array elements is also possible.For example:

[3833] ram int 7 w[23];

[3834] int 5 x[4];

[3835] int 3 y;

[3836] unsigned int 1 z;

[3837] y=w[10][4:2];

[3838] z−x[2][0];.

[3839] Here, the 10 is the entry in the RAM and the 4:2 selects threebits from the middle of the value in the RAM. Similarly, z is set to theleast significant bit in the x[2] variable.

[3840] Width Operator

[3841] The width( ) operator returns the width of an expression. It is acompile time constant. For example:

[3842] x=y<−width(x);

[3843] This takes the least significant bits of y and assigns them to x.The width( ) operator ensures that the correct number of bits is takenfrom y to match the width of x.

[3844] Arithmetic Operators

[3845] The following arithmetic operators are provided in Handel-C:Operator Meaning + Addition − Subtraction * Multiplication / Division %Modulus arithmetic

[3846] Any attempt to perform one of these operations on two expressionsof differing widths or types results in a compiler error. For example:

[3847] int 4 w;

[3848] int 3 x;

[3849] int 4 y;

[3850] unsigned 4 z;

[3851] y=w+x; // ILLEGAL

[3852] z=w+y; // ILLEGAL

[3853] The first statement is illegal because w and x have differentwidths. The second statement is illegal because w and y are signedintegers and z is an unsigned integer. All operators return results ofthe same width as their operands. Thus, all overflow bits are lost. Forexample:.

[3854] unsigned int 8 x;

[3855] unsigned int 8 y;

[3856] unsigned int 8 z;

[3857] x=128;

[3858] y=192;

[3859] z=2;

[3860] x=x+y;

[3861] z=z * y;

[3862] This example results in x being set to 64 and z being set to 128.By using the bit manipulation operators to expand the operands, it ispossible to obtain extra information from the arithmetic operations. Forinstance, the carry bit of an addition or the overflow bits of amultiplication may be obtained by first expanding the operands to themaximum width required to contain this extra information. For example:

[3863] unsigned int 8 u;

[3864] unsigned int 8 v;

[3865] unsigned int 9 w;

[3866] unsigned int 8 x;

[3867] unsigned int 8 y;

[3868] unsigned int 16 z;

[3869] w=(0@ u)+(0@ v);

[3870] z=(0@ x) * (0@ y);

[3871] In this example, w and z contain all the information obtainablefrom the addition and multiplication operations. Note that the constantzeros do not require a width specification because the compiler caninfer their widths form the usage. The zeros in the first assignment maybe 1 bit wide because the destination is 9 bits wide while the sourceoperands are only 8 bits wide. In the second assignment, the zeroconstants may be 8 bits wide because the destination is 16 bits widewhile the source operands are only 8 bits wide.

[3872] Operator Precedence

[3873] Precedence of operators is as expected from conventional C. Forexample:

[3874] x=x+y * z;

[3875] This performs the multiplication before the addition. Bracketsmay be used to ensure the correct calculation order as in conventionalC.

[3876] Relational Operators

[3877] The following relational operators are provided in Handel-C:Operator Meaning == Equal to != Not equal to < Less than > Greater than<= Less than or equal >= Greater than or equal

[3878] These operators compare values of the same width and return asingle bit wide unsigned int value of 0 for false or 1 for true. Thismeans that the following conventional C code is invalid:

[3879] int 8 w, x, y, z;

[3880] w=x+(y>z); // NOT ALLOWED

[3881] Instead, one should write:

[3882] w=x+(0@(y>z));

[3883] Signed/Unsigned Compares

[3884] Signed/signed compares and unsigned/unsigned compares are handledautomatically. Mixed signed and unsigned compares are not handledautomatically. For example:

[3885] unsigned 8 x;

[3886] int 8 y;

[3887] if (x>y) // Not allowed

[3888] . . .

[3889] To compare signed and unsigned values one may sign extend each ofthe parameters. The above code can be rewritten as:

[3890] unsigned 8 x;

[3891] int 8 y;

[3892] if ((int)(0@x)>(y[7]@y))

[3893] Implicit Compares

[3894] The Handel-C compiler inserts implicit compares with zero if avalue is used as a condition on its own. For example:

[3895] while (1)

[3896] {

[3897] . . .

[3898] while (1 !=0)

[3899] {

[3900] . . .

[3901] }

[3902] Logical Operators

[3903] The following logical operators are provided in Handel-C:Operator Meaning && Logical and ∥ Logical or ! Logical not

[3904] These operators are provided to combine conditions as inconventional C. Each operator takes 1 -bit unsigned operands and returnsa 1-bit unsigned result. Note that the operands of these operators neednot be the results of relational operators. For example:

[3905] if (x∥y>z)

[3906] w=0;

[3907] In this example, the variable x need not be 1 bit wide—if it iswider, the Handel-C compiler inserts a compare with 0. As inconventional C, the condition of the if statement is true if x is notequal to 0 or y is greater than z. This feature allows some familiarlooking conventional C constructs. For example:

[3908] while (x∥y)

[3909] {

[3910] . . .

[3911] }

[3912] Bitwise logical Operators

[3913] The following bitwise logical operators are provided in Handel-C:Operator Meaning & Bitwise and | Bitwise or {circumflex over ( )}Bitwise exclusive or ˜ Bitwise not

[3914] these operators perform bitwise logical operations on values.Both operands may be of the same type and width: the resulting value mayalso be this type and width. For example:

[3915] unsigned int 6 w;

[3916] unsigned int 6 x;

[3917] unsigned int 6 y;

[3918] unsigned int 6 z;

[3919] w=0b101010;

[3920] x=0b011100;

[3921] y=w&x;

[3922] z w|x;

[3923] w=w^ ˜x;

[3924] This example results in y having the value 0b0010000, z havingthe value 0b11110 and w having the value 0b001001.

[3925] Conditional Operator

[3926] Handel-C provides the conditional expression construct familiarfrom conventional C. Its format is: Expression ? Expression: Expression

[3927] The first expression is evaluated and if true, the wholeexpression evaluates to the result of the second expression. If thefirst expression is false, the whole expression evaluates to the resultof the third expression. For example:

[3928] x=(y>z) ? y : z;

[3929] This sets x to the maximum of y and z. This code is directlyequivalent to:

[3930] if(y>Z)

[3931] x=y;

[3932] else

[3933] x=z;

[3934] The advantage of using this construct is that the result is anexpression so it can be embedded in a more complex expression. Forexample:

[3935] x=((y>z) ?y:z)+4;

[3936] Casting of Expression Types

[3937] The following piece of Handel-C is invalid:

[3938] int 4 x;/ Range of x: −8 . . . 7

[3939] unsigned int 4 y; // Range of y: 0 . . . 15

[3940] x=y; // Not allowed

[3941] This is because x is a signed integer while y is an unsignedinteger. When generating hardware, it is not clear what the compilershould do here. It could simply assign the 4 bits of y to the 4 bits ofx or it could extend y with an extra zero as its most significant bit topreserve its value and then assign these 5 bits to x assuming x wasdeclared to be 5 bits wide. To see the difference, consider the casewhen y is 10. By simply assigning these 4 bits to a signed integer, aresult of −6 would be placed in x. A better solution might be to extendy to a five bit value by adding a 0 bit as its MSB to preserve the valueof 10. The solution adopted by Handel-C is not to allow automaticconversions between signed and unsigned values to avoid this confusion.Instead, values may be ‘cast’ between types to ensure that theprogrammer is aware that a conversion is occurring that may alter themeaning of a value. The above example then becomes:

[3942] int 4 x;

[3943] unsigned int 4 y;

[3944] x=(int 4)y;

[3945] It is now clear that the value of x is the result of treating the4 bits extracted from y as a signed integer. One can also cast to a typeof undefined width. For example:

[3946] int4x;

[3947] unsigned int undefined y;

[3948] x=(int undefined)y;

[3949] Here, the compiler may infer that y may be 4 bits wide. Castingcannot be used to change the width of values. For example,

[3950] this is not allowed:

[3951] unsigned int 7 x;

[3952] int 12 y;

[3953] y=(int 12)x; //Not allowed

[3954] Instead, the conversion should be done explicitly:

[3955] y=(int 12)(0 @ x);

[3956] Here, the concatenation operation produces a 12-bit unsignedvalue. The casting then changes this to a 12-bit signed integer forassignment to y. Again, this is to ensure that the programmer is awareof such conversions. To illustrate why this is important, consider thefollowing example:

[3957] int 7 x;

[3958] unsigned int 12 y;

[3959] x=−5;

[3960] y=(unsigned int 12)x;.

[3961] Here, the Handel-C compiler could take two equally viable routes.One would be to sign extend the value of x and produce the result 4091.The second would be to zero pad the value of x and produce the value of123. Since neither method can preserve the value of x in y Handel-Cperforms neither automatically. Rather, it is left up to the programmerto decide which approach is correct in a particular situation and towrite the expression accordingly

Function

[3962] Introduction

[3963] Functions are similar to functions in ISO-C. Handel-C has beenextended to provide arrays of functions and inline functions. Arrays offunctions provide multiple copies of a function. One can select whichcopy is used at any time. Inline functions are similar to macros in thatthey are expanded wherever they are used. Functions take arguments andreturn values. A function that does not return a value is of type void.The default return type is int undefined.

[3964] When a function is declared or defined, it has a parameter list,which describes the type of arguments that it expects to receive.Functions that do not take arguments have void as their parameter list.E.g. void main(void)

[3965] As in ISO-C, function arguments are passed by value. This meansthat a local copy is created that is only in scope within the function.Changes take place on this copy. To access a variable outside thefunction, one may pass the function a pointer to that variable. A localcopy may be made of the pointer, but it may still point to the samevariable. This is known as passing by reference. Architectural types(hardware constructs) may be passed by reference (a pointer to oraddress of the construct). The only architectural type that can bepassed to or returned by a function by value is a signal. All others(and structures or unions containing them) may be passed by reference.Arrays and functions can also only be passed by reference.

[3966] Function Definitions and Declarations

[3967] Functions are defined as in ISO-C. The function declarationconsists of the function name, and names and types for its parametersand return value. The definition of a function consists of itsdeclaration plus the code body that it performs when it is called.

[3968] returnType Name(parameterList)

[3969] {

[3970] declarations

[3971] statements

[3972] }

[3973] If the declaration is followed by a semi-colon, it is a functionprototype. This tells the compiler the types of arguments that thefunction expects so it can check that the function is used correctlywithin the rest of the file.

[3974] returnType Name(parameterList);

[3975] The names in a function prototype are only in scope in theprototype. One can use different names in the definition of the functionand function calls. Functions may be declared (prototyped) in every filethat they are used in, though they should only be defined once. It iscommon to put function prototypes into a header file and #include thatin every file where they are used.

[3976] Scope

[3977] Functions cannot be defined within other functions. By default,functions are extern (they can be used anywhere). Functions can also bedefined as static (they can only be used in the file in which they aredefined).

[3978] Arrays of Functions

[3979] An array of functions is a collection of identical functions. Itis not the same as an array of function pointers (each of whose elementscan point to a different function). Function arrays allow functions tobe copied and shared neatly. Here is a declaration of a simple functionarray:

[3980] unsigned func[2] (unsigned x, unsigned y)

[3981] return (x+y);

[3982] }

[3983] The syntax is a normal function declaration, with square bracketsadded to specify that this is an array declaration as well as a functiondeclaration. The general form of a function array declaration is:

[3984] returntype Name[Size] (parameterList)

[3985] One can also declare a function array in a prototype. This meansthat one can declare a function func in one file, and an array offunctions of type func in another file

[3986] void func[n] (void);

[3987] A function array allows one to run different copies of thefunction in parallel. Without this construct, the only safe way to run afunction in parallel with itself would be to explicitly declare twofunctions with different names. This would not be so neat and intuitive.

[3988] Example

[3989] set clock=external “P1”;

[3990] // Function array prototype unsigned func[2] (unsigned x,unsigned y);

[3991] // Main program

[3992] void main(void)

[3993] }

[3994] unsigned a, b, c, d, e, f;

[3995] unsigned short r1, r2, r3, r4;

[3996] unsigned result;

[3997] par

[3998] {

[3999] a=12;

[4000] b=22;

[4001] c=32;

[4002] d=42;

[4003] e=52;

[4004] f=62;

[4005] }

[4006] par

[4007] {

[4008] r1=func[0] (a, b);

[4009] r2=func[1] (c, d);

[4010] }

[4011] par

[4012] }

[4013] r3=func[0] (e, f)

[4014] r4=func[1] (r1, r2);

[4015] result=func[0] r3, r4];

[4016] // Function array definition

[4017] unsigned func[2] (unsigned x, unsigned y)

[4018] {

[4019] return (x+y);

[4020] Function Pointers

[4021] These are a very powerful, yet potentially confusing feature. Insituations where any one of a number of functions can be called at aparticular point, it is neater and more concise to use a functionpointer, where the alternative might be a long if-else chain, or a longswitch statement. For example, consider this program:

[4022] unsigned 1 check(short int *a, short int *b,

[4023] unsigned 1 (*chk)(short int *, short int *));

[4024] unsigned 1 addeven(const short int *x, const short int *y);

[4025] unsigned 1 multeven(const short int *x, const short int *y);

[4026] unsigned 1 diveven(const short int *x, const short int *y);

[4027] unsigned 1 modeven(const short int *x, const short int *y);

[4028] void main(void)

[4029] {

[4030] short int m, n;

[4031] unsigned 2 choice;

[4032] unsigned 1 result;

[4033] unsigned 1 (*p)(const short *, const short *);

[4034] par

[4035] {

[4036] m=19;

[4037] n=47;

[4038] do

[4039] {

[4040] switch (choice)

[4041] {

[4042] case 0:

[4043] p=addeven;

[4044] break;

[4045] case 1:

[4046] p=multeven;

[4047] break;

[4048] case 2:

[4049] p=diveven;

[4050] break;

[4051] case 3.

[4052] p=modeven;

[4053] break;

[4054] }

[4055] default:

[4056] break;

[4057] }

[4058] par

[4059] {

[4060] result=check(&m, &n, p); choice++;

[4061] }.Handel-C Language

[4062] }

[4063] while (choice)

[4064] delay;

[4065] }

[4066] unsigned 1 check(short int *a, short int *b,

[4067] unsigned 1 (*chk)(short int *, short int *))

[4068] {

[4069] return (*chk)(a, b);

[4070] }

[4071] unsigned 1 adeven(const short int *x, const short int *y)

[4072] {

[4073] return (unsigned) (*x+*y) [0];

[4074] unsigned 1 multeven(const short int *x, const short int *y)

[4075] {

[4076] return (unsigned) (*x * *y)[0];

[4077] }

[4078] unsigned 1 diveven(const short int *x, const short int *y)

[4079] {

[4080] return (unsigned) (*x/*y)[0];

[4081] }

[4082] unsigned 1 modeven(const short int *x, const short int *y)

[4083] }

[4084] return (unsigned) (*x % *y) [0];

[4085] The function addeven checks whether the sum of two numbers iseven. Similar checks are carried out by multeven (product of twonumbers), diveven (division) and modeven (modulus). The function checksimply calls the function whose pointer it receives, with the argumentsit receives. This gives a consistent interface to the xxxeven functions.Pay close attention to the declaration of check, and of function pointerp. The parentheses around *p (and *chk in the declaration of check) arenecessary for the compiler to make the correct interpretation.

[4086] Indirection Techniques Function pointers can be assigned with orwithout the address operator & (similar to assigning array addresses).Functions pointed to can be called with or without the indirectionoperator. In the code above, the function name was assigned to thepointer without the &

[4087] p=addeven;

[4088] One may wish to use the & format for clarity:

[4089] p=&adeven;

[4090] Inside check, the function pointed to by p was called by writing.

[4091] (*cbk)(a,b);

[4092] This could also have written in the shorthand form:

[4093] chk(a,b);

[4094] The first form is preferable, as it tips off anyone reading thecode that a function pointer is being used.

[4095] Inside the main program body, check was called like this.

[4096] check(&m, &n, p);

[4097] It could have been written like this,

[4098] check(&m, &n, xxxeven);

[4099] eliminating the need for an additional pointer variable. Here isthe main section written using this form of expression:

[4100] void main(void)

[4101] {

[4102] short int m, n;

[4103] unsigned 2 choice;

[4104] unsigned 1 result;

[4105] par

[4106] {

[4107] m=19;

[4108] n=47;

[4109] }

[4110] do

[4111] {

[4112] switch (choice)

[4113] case 0:

[4114] result=check(&m, &n, adeven);

[4115] break;

[4116] case 1:

[4117] result=check(&m, &n, multeven);

[4118] break;

[4119] case 2:

[4120] result=check(&m, &n, diveven);

[4121] break;

[4122] case 3:

[4123] result=check(&m, &n, modeven);

[4124] break;

[4125] default:

[4126] break;

[4127] choice++;

[4128] }

[4129] while (choice)

[4130] delay;

[4131] Restrictions on Functions

[4132] Shared Code

[4133] Functions may not be shared by two different parts of the programon the same clock cycle. For example:

[4134] int func(x, y);

[4135] par

[4136] {

[4137] a=func(b, c);

[4138] {

[4139] b=foo;

[4140] d=func(e, f); // NOT ALLOWED

[4141] }

[4142] }

[4143] int func(int x, int y)

[4144] }

[4145] if (x==y)

[4146] delay;

[4147] else

[4148] {

[4149] x=x % y;

[4150] }

[4151] x*=10;

[4152] return (x)

[4153] }

[4154] This is not allowed because part of the single function is usedtwice in the same clock cycle. This overlapping usage is not detected bythe compiler, as it is a run-time error. It is therefore theprogrammer's responsibility to ensure that code usage does not overlap.This may be done by declaring functions to be inline (are expandedwhenever they are used) or declaring an array of functions, one to beused in each parallel branch.

[4155] inline int func(x, y);

[4156] par

[4157] {

[4158] a=func(b, c);

[4159] {

[4160] b=foo;

[4161] d=func(e, f);

[4162] }

[4163] }

[4164] or

[4165] int func [3] (x, y);

[4166] par

[4167] {

[4168] a=func[0] (b, c)

[4169] {

[4170] b=foo;

[4171] d=func[1] (e, f)

[4172] }

[4173] }

[4174] More details on timing of Handel-C programs and more details ofhow one can tell which clock cycle operations are performed will be setforth later.

[4175] Recursion

[4176] Due to the absence of a stack in Handel-C, functions cannot berecursive. If a person calls a function within that function's body, thecompiler generates an error

Macros

[4177] Introduction

[4178] As mentioned in previous sections, the Handel-C compiler passessource code through a standard C preprocessor before compilationallowing the use of #define to define constants and macros in the usualmanner. There are some limitations to this approach. Since thepreprocessor can only perform textual substitution, some useful macroconstructs cannot be expressed. For example, there is no way to createrecursive macros using the preprocessor.

[4179] Handel-C provides additional macro support to allow more powerfulmacros to be defined (for example, recursive macro expressions). Inaddition, Handel C supports shared macros to generate one piece ofhardware which is shared by a number of parts of the overall programsimilar to the way that procedures allow conventional C to share onepiece of code between many parts of a conventional program. This sectionof the present description details how to define macros and sharedhardware.

[4180] Macro Expressions

[4181] Macros may be used to replace expressions to avoid tediousrepetition. Handel-C provides some powerful macro constructs to allowcomplex expressions to be generated simply.

[4182] Constant Macro Expressions

[4183] Constant macro expressions are of two types:

[4184] simple constant equivalent to #define

[4185] a constant expression

[4186] Constant

[4187] This first form of the macro is a simple expression. For example:

[4188] macro expr DATA_WIDTH=15;

[4189] int DATA_WIDTH x;

[4190] This form of the macro is similar to the #define macro. WheneverDATA_WIDTH appears in the program, the constant 15 is inserted in itsplace.

[4191] Constant Expression

[4192] To provide a more general solution, one can use a realexpression. For example:

[4193] macro expr sum=(x+y)@ (y+z);

[4194] v=sum;

[4195] w=sum;

[4196] Parameterized Macro Expressions

[4197]FIG. 57A-2 illustrates a method 5750 for parameterizedexpressions, in accordance with various embodiments of the presentinvention. In general, a plurality of first variables are defined withreference to variable widths. See operation 5752. A plurality of secondvariables are also defined without reference to variable widths, asindicated in operation 5754. In an aspect of the present invention, thefirst and second variables may be included in a library.

[4198] Computer code is then compiled including the first and secondvariables. Note operation 5756. As such, the variable widths of thesecond variables may be inferred from the variable widths of the firstvariables. See operation 5758. In one embodiment of the presentinvention, the variable widths of the second variables may be inferredduring a routine that reconciles the first variables with the secondvariables in the library. As an option, a relation may be definedbetween the first variables and the second variables.

[4199] In yet another aspect, the first variables may be further definedwith reference to data types, the second variables may be definedwithout reference to the data types, and the data types of the secondvariables may be inferred from the data types of the first variables. Ineven another aspect of the present invention, the first variables may befurther defined with reference to array size, the second variables maybe defined without reference to the array size, and the array size ofthe second variables may be inferred from the array size of the firstvariables. In yet another aspect, the first variables may be furtherdefined with reference to pipeline depth, the second variables may bedefined without reference to the pipeline depth, and the pipeline depthof the second variables may be inferred from the pipeline depth of thefirst variables.

[4200] It should be noted that the above concept may be applied in moregeneral contexts per the desires of the user. For example, anapplication may be defined with a first variable where the firstvariables' width is unresolved. Thereafter, the application may bestored in a library, and computer code may be compiled including thefirst variable. In one embodiment of the present invention, a pluralityof libraries may be used to organize functional components of predefinedfunctions.

[4201] As such, the variable width of the first variable may be resolvedas the application is utilized in any desired manner. For example, thevariable width of the first variable may be resolved utilizingpredefined rules during compilation. Still yet, a plurality of variablesmay be resolved dynamically during compilation. As yet another option,the variable widths of the first variable may change in response to thecompilation in a first application or a second application. As anoption, the first variable may be defined with no reference to a datatype. Accordingly, the data type of the first variable is resolveddynamically as the compilation proceeds. In a similar manner, the firstvariable may be defined without reference to array size. Further, thearray size of the second variables may be resolved dynamically duringcompilation as the first variable is used by an application.

[4202] More information regarding the above concept will now be setforth in greater detail.

[4203] Handel-C also allows macros with parameters. For example:

[4204] macro expr add3(x)=x+3;

[4205] y=add3(z);

[4206] This is equivalent to the following code:

[4207] y=z+3;

[4208] Again, this form of the macro is similar to the #define macro inthat every time the add3( ) macro is referenced, it is expanded in themanner shown above. In other words, in this example, an adder isgenerated in hardware every time the add3( ) macro is used.

[4209] The Select Operator

[4210] Handel-C provides a select( . . . ) operator which is used tomean ‘select at compile time’. Its general usage is: select(Expression,Expression, Expression) Here, the first expression may be a compile timeconstant. If the first expression evaluates to true then the Handel-Ccompiler replaces the whole expression with the second expression. Ifthe first expression evaluates to false then the Handel-C compilerreplaces the whole expression with the second expression. The differencebetween this and the ?: operators is best illustrated with an example.

[4211] w=(width(x)==4? y: z);

[4212] This example generates hardware to compare the width of thevariable x with 4 and set w to the value of y or z depending on whetherthis value is equal to 4 or not. This is probably not what was intendedin this case because both width(x) and 4 are constants. What wasprobably intended was for the compiler to check whether the width of xwas 4 and then simply replace the whole expression above with y or zaccording to the value. This can be written as follows:

[4213] w=select(width(x)==4, y, z);

[4214] In this example, the compiler evaluates the first expression andreplaces the whole line with either w=y; or w=z;. No hardware for theconditional is generated.

[4215] A more useful example can be seen when macros are combined withthis feature. For example:

[4216] macro expr adjust(x, n)=

[4217] select(width(x)<n, (0@ x), (x<-n));

[4218] unsigned 4 a;

[4219] unsigned 5 b;

[4220] unsigned 6 c;

[4221] b=adjust(a, width(b));

[4222] b=adjust(c, width(b));

[4223] This example is for a macro that equalizes widths of variables inan assignment. If the right hand side of an assignment is narrower thanthe left hand side then the right hand side may be padded with zeros inits most significant bits. If the right hand side is wider than the lefthand side, the least significant bits of the right hand side may betaken and assigned to the left hand side.

[4224] The select( . . . ) operator is used here to tell the compiler togenerate different expressions depending on the width of one of theparameters to the macro. The last two lines of the example could havebeen written by hand as follows:

[4225] b=0@ a;

[4226] b=c<-5;

[4227] However, the macro comes into its own if the width of one of thevariables changes. For example, suppose that during debugging, it isdiscovered that the variable a is not wide enough and needs to be 8 bitswide to hold some values used during the calculation. By using themacro, the only change required would be to alter the declaration of thevariable a. The compiler would then replace the statement b=0@ a; withb=a<−5; automatically.

[4228] This form of macro also comes in useful is when variables ofundefined width are used. If the compiler is used to infer widths ofvariables, it may be tedious to work out by hand which form of theassignment is required. By using the select( . . . ) operator in thisway, the correct expression is generated without one having to know thewidths of variables at any stage.

[4229] If select

[4230] Syntax

[4231] ifselect (condition) ps statement 1

[4232] [else

[4233] statement 2]

[4234] ifselect checks the result of a compile-time constant expressionat compile time. If the condition is true, the following statement orcode block is compiled. If false, it is dropped and an else conditioncan be compiled if it exists. Thus, whole statements can be selected ordiscarded at compile time, depending on the evaluation of theexpression.

[4235] The ifselect construct allows one to build recursive macros, in asimilar way to select. It is also useful inside replicated blocks ofcode as the replicator index is a compile-time constant. Hence, one canuse ifselect to detect the first and last items in a replicated block ofcode and build pipelines.

[4236] Example

[4237] int 12 a;

[4238] int 13 b;

[4239] int undefined c;

[4240] ifselect(width(a)>=width(b))

[4241] c=a;

[4242] else

[4243] c=b;

[4244] c is assigned to by either a or b, depending on their widthrelationship.

[4245] Pipeline Example

[4246] unsigned init;

[4247] unsigned q[151];

[4248] unsigned 31 out;

[4249] init=57;

[4250] par (r=0;r<16;r++)

[4251] {

[4252] ifselect(r==0)

[4253] q[r]=init;

[4254] else ifselect(r==15)

[4255] out=q[r−1];

[4256] else

[4257] q[r]=q[r−1];

[4258] }

[4259] Recursive Macro Expressions

[4260] A serious limitation with preprocessor macros (those defined with#define) is their inability to generate recursive expressions. Bycombining Handel-C macros (those defined with macro expr) and theselect( . . . ) operator discussed above, recursive macros can be usedto simply express complex hardware. This type of macro is particularlyimportant in Handel-C where the exact form of the macro may depend onthe width of a parameter to the macro. As an example, a sign extensionof a variable is taken. When assigning a narrow signed variable to awider variable, the most significant bits of the wide variable should bepadded with the sign bit (MSB) of the narrow variable. For example, the4-bit representation of −2 is 0b 1110. When assigned to an 8-bit widevariable, this should become 0b11111110. In contrast, the 4-bitrepresentation of 6 is 0b0110. When assigned to an 8-bit wide variable,this should become 0b00000110. In this example, the following code wouldsuffice:

[4261] int 8 x;

[4262] int 4 y;

[4263] x=y[3]@ y[3]@ y[3]@ y[3]@ y;

[4264] As one can see, this can rapidly become tedious for variablesthat differ by a significant number of bits. Also, what if the exactwidths of the variables are not known? What is needed is a macro to signextend a variable. For example:

[4265] macro expr copy(x, n)=

[4266] select(n==1, x, (x @ copy(x, n−1)));

[4267] macro expr extend(y, m)=

[4268] copy(y[width(y)−1], m-width(y)) @ y;

[4269] int a;

[4270] int b; // Where b is known to be wider than a

[4271] b=extend(a, width(b));

[4272] Here, the copy macro generates n copies of the expression xconcatenated together. The macro is recursive and uses the select( . . .) operator to evaluate whether it is on its last iteration (in whichcase it just evaluates to the expression) or whether it should continueto recurse by a further level. The extend macro simply concatenates thesign bit of its parameter m-k times onto the most significant bits ofthe parameter. Here, m is the required width of the expression y and kis the actual width of the expression y. The final assignment correctlysign extends a to the width of b for any variable widths where width(b)is greater than width(a).

[4273] Recursive Macro Expressions: a Larger Example

[4274] A second example of the use of recursive macro expressions is nowgiven to illustrate the generation of large quantities of hardware fromsimple macros. The example used is that of a multiplier whose widthdepends on the parameters of the macro. Although Handel-C includes amultiplication operator as part of the language, this example serves asa starting point for generating large regular hardware structures usingmacros.

[4275] The multiplier generates the hardware for a single cycle longmultiplication operation from a single macro. The source code is:

[4276] macro expr multiply(x, y)=

[4277] select(width(x)==0, 0,

[4278] multiply(x\\ 1, y <<1)+

[4279] (x[0]==1 ? y: 0));

[4280] a=multiply (b, c);

[4281] At each stage of recursion, the multiplier tests whether thebottom bit of the x parameter is 1. If it is then y is added to the‘running total’. The multiplier then recurses by dropping the LSB of xand multiplying y by 2 until there are no bits left in x. The overallresult is an expression that is the sum of each bit in x multiplied byy. This is the familiar long multiplication structure. For example, ifboth parameters are 4 bits wide, the macro expands to:

[4282] a=((b \\ 3)[0]==1 ? c<<3 : 0) +

[4283] ((b \\ 2)[0]==1 ? c<<2: 0) +

[4284] ((b \\ 1)[0]==1 ? c<<1 : 0) +

[4285] (b[0]==1 ? c: 0);

[4286] This code is equivalent to:

[4287] a=((b & 8)==8 ? c*8 : 0) +

[4288] (b & 4)==4 ? c*4 : 0) +

[4289] ((b & 2)==2 ? c*2 : 0) +

[4290] ((b & 1)==1 ? c : 0);

[4291] which is a standard long multiplication calculation.

[4292] Shared Expressions

[4293] By default, Handel-C generates all the hardware required forevery expression in the whole program. In many programs, this means thatlarge parts of the hardware may be idle for long periods. The sharedexpression allows hardware to be shared between different parts of theprogram to decrease hardware usage. The shared expression has the sameformat as a macro expression but does not allow recursion. An exampleprogram where shared expressions are extremely useful is:

[4294] a=b * c;

[4295] d=e * f;

[4296] g=h * i;

[4297] Here, three multipliers may be generated but each one may only beused once and none of them simultaneously. This is a massive waste ofhardware. The way to improve this program is:

[4298] shared expr mult(x, y)=x * y,

[4299] a=mult(b, c);

[4300] d=mult(e, f);

[4301] g=mult(h, i);

[4302] In this example, only one multiplier is built and it is used onevery clock cycle which is a better use of hardware. (In fact, the aboveexample could be built as three multipliers executing in parallel if themaximum performance is required).

[4303] It is not always the case that less hardware is generated byusing shared expressions because multiplexers may need to be built toroute the data paths. Some expressions use less hardware than themultiplexers associated with the shared expression.

[4304] Using Recursion to Generate Shared Expressions

[4305] Although shared expressions cannot use recursion directly, macroexpressions can be used to generate hardware which can then be sharedusing a shared expression. For example, to share the recursivemultiplier macro example above one could write:

[4306] macro expr multiply(x, y)=

[4307] select(width(x)==0, 0,

[4308] multiply(x \\ 1, y <<1) +

[4309] (x[0] 1 ? y: 0));

[4310] shared expr mult(x, y)=multiply(x, y);

[4311] a=mult(b, c);

[4312] d=mult(e, f);

[4313] Here, the macro expression builds a multiplier and the sharedexpression allows that hardware to be shared between the twoassignments.

[4314] Restrictions on Shared Expressions

[4315] A limitation to shared expressions is that they may not be sharedby two different parts of the program on the same clock cycle. Forexample:

[4316] shared expr mult(x, y)=x * y;

[4317] par

[4318] {

[4319] a=mult(b, c);

[4320] d=mult(e, f);// NOT ALLOWED

[4321] }

[4322] This is not allowed because the single multiplier is used twicein the same clock cycle. This becomes an important skill when usingshared expressions.

[4323] let ...in

[4324] The Handel-C constructs let and in allow one to declare macroexpressions within macro expressions. In this way, complex macros may bebroken down into simple ones, whilst still being grouped together in asingle block of code. They also provide easy sharing of recursivemacros. The let keyword starts the declaration of a local macro; the inkeyword ends the declaration and defines its scope.

[4325] Example

[4326] macro expr Fred(x)=

[4327] let macro expr y=x*2; in

[4328] y+3;//Returns x*2+3

[4329] The top line defines the macro name and parameters. The secondline defines y within the macro definition. The last line expresses thevalue of the macro in full.

[4330] Independent let ...in definitions

[4331] macro expr op(a, b)=

[4332] let macro expr t2(x)=x * 2; in

[4333] let macro expr d3(x)=x / 3; in

[4334] let macro expr t4(x)=x * 4; in

[4335] t2(a) +d3(b) +t4(a - b) +t2(b - a);

[4336] is equivalent to writing

[4337] macro expr op(a, b)=(a * 2) +(b /3) +((a-b) *4) +

[4338] ((b-a) * 2);

[4339] Related let ...in Definitions

[4340] macro expr op(a, b)=

[4341] let macro expr sum(x, y)=x+y; in

[4342] let macro expr mult(x, y)=x * sum(x, y); in

[4343] mult(a, b)−(b * b);

[4344] sum is defined within the macro definition, then mult is definedusing

[4345] sum. This example is equivalent to:

[4346] macro expr op(a, b)=(a * (a +b))−(b * b);

[4347] Shared Recursive Macro

[4348] A recursive multiplier illustrating the way in which let...in canbe used to share recursive macros.

[4349] shared expr mult(p, q)=

[4350] let macro expr multiply(x, y)=

[4351] select(width(x)==0, 0, multiply(x \\ 1, y<<1)

[4352] +(x[0]==1 ? y: 0)); in

[4353] multiply(p, q);.

[4354] Macro Procedures

[4355] Macros may be used to replace statements to avoid tediousrepetition. Handel-C provides simple macro constructs to expand singlestatements into complex blocks of code. The general syntax of macroprocedures is:

[4356] macro proc Name(Params) Statement

[4357] For example:

[4358] macro proc output(x, y)

[4359] {

[4360] out! x;

[4361] out! y;

[4362] }

[4363] output(a+b, c * d);

[4364] output(a+b, c * d);

[4365] This example writes the two expressions a+b and c*d twice to thechannel out. This example also illustrates that the statement may be acode block—in this case two instructions executed sequentially. Macroprocedures generate the hardware for their statement every time they arereferenced. The above example expands to 4 channel output statements.Macro procedures differ from preprocessor macros in that they are notsimple text replacements. The statement section of the definition may bea valid Handel-C statement. For example:

[4366] #define test(x,y) if (x!=(y<<2))

[4367] test(a,b)

[4368] {

[4369] a++;

[4370] }

[4371] else

[4372] {

[4373] b++;

[4374] }

[4375] This is a valid preprocessor macro definition. However, thefollowing code is not allowed:

[4376] macro proc test(x,y) if(x!=(y<<2));

[4377] test(a,b)// NOT ALLOWED

[4378] {

[4379] a++;

[4380] }else

[4381] {

[4382] b++;

[4383] }

[4384] Here, the macro procedure is not defined to be a completestatement so the Handel-C compiler generates an error. This restrictionprovides protection against writing code such as these examples which isgenerally unreadable and difficult to maintain.

[4385] Macro Prototypes

[4386] As with functions, macros may be prototyped. This allows one todeclare them in one file and use them in another. A macro prototypeconsists of the name of the macro plus a list of the names of itsparameters. E.g.

[4387] macro proc work(x, y);

[4388] shared expr mult(p, q);.10 Timing and efficiency information.

Timing Information

[4389] Introduction

[4390] A Handel-C program executes with one clock source for each mainstatement. It is important to be aware exactly which parts of the codeexecute on which clock cycles. This is not only important for writingcode that executes in fewer clock cycles but may mean the differencebetween correct and incorrect code when using Handel-C's parallelism.Knowing about clock cycles also becomes important when consideringinterfaces to external hardware. This subject is covered in greaterdetail later but it is important to understand timing issues beforemoving on to implementing such interfaces because it likely that theexternal device may place constraints on when signals should change.

[4391] This section of the present description also deals with thesubject of overall performance. It shall be seen that avoiding certainconstructs has a dramatic influence on the maximum clock rate that theHandel-C program can run at and some guidelines are given for improvingthe hardware performance. An example is given that covers theconsiderations for real time constraints on a system.

[4392] Clock Cycle Timing of Language Constructs

[4393] This section deals with the analysis of a program in terms of thenumber of clock cycles it takes to execute. The Handel-C language hasbeen designed so that an experienced programmer can immediately tellwhich instructions execute on which clock cycles. This informationbecomes very important when the program contains multiple interactingparallel processes.

[4394] Statement Timing

[4395] The basic rule for working out the number of cycles used in aHandel-C program is:

[4396] Assignment and delay take 1 clock cycle.

[4397] Everything else is free.

[4398] What this means is that every time one write an assignmentstatement or a delay statement, one use one clock cycle but one canwrite any other piece of code and not use any clock cycles to executeit. The only exception is channel communication which takes one clockcycle only if both parties are ready to communicate in the same clockdomain. This means that if one parallel branch is ready to output on achannel when another branch is ready to receive then it takes one clockcycle for the data to be assigned to the variable in the inputstatement. If one of the branches is not ready for the data transferthen execution of the other branch waits until both branches becomeready. Even if both branches are ready for the transfer then one clockcycle is used because channel input is a form of assignment. Some simpleexamples with their timings are shown below.

[4399] Statements

[4400] x=y;

[4401] x=(((y * z) +(w *v))<<2)<-7;

[4402] Each of these statements takes one clock cycle. Notice that eventhe most complex expression can be evaluated in a single clock cycle.Handel-C simply builds the combinatorial hardware to evaluate suchexpressions; they do not need to be broken down into simpler assemblyinstructions as would be the case for conventional C.

[4403] Parallel Statements

[4404] par

[4405] {

[4406] x=y;

[4407] a=b * c;

[4408] This code executes in a single cycle because each branch of theparallel statement takes only one clock cycle. This example illustratesthe benefits of parallelism. One can have as many non-interdependentinstructions as he or she wishes in the branches of a parallelstatement. The total time for execution is the length of time that thelongest branch takes to execute. For example:

[4409] par

[4410] {

[4411] x=y;

[4412] {

[4413] a=b;

[4414] c=d;

[4415] }

[4416] }

[4417] This code takes two clock cycles to execute. On the first cycle,x=y and a=b take place. On the second clock cycle, c=d takes place.Since both branches of the par statement may complete before the parblock can complete, the first branch delays for one clock cycle whilethe second instruction in the second branch is executed.

[4418] While loop

[4419] x=5;

[4420] while (x>0)

[4421] {

[4422] x−−;

[4423] }

[4424] This code takes a total of 6 clock cycles to execute. One cycleis taken by the assignment of 5 to x. Each iteration of the while looptakes 1 clock cycle for the assignment of x−1 to x and the loop body isexecuted 5 times. The condition of the while loop takes no clock cyclesas no assignment is involved.

[4425] For loop

[4426] for (x=0; x <5; x++)

[4427] {

[4428] a+=b;

[4429] b *=2:

[4430] }

[4431] As discussed earlier, this code has an almost direct equivalent:

[4432] {

[4433] x=0;

[4434] while (x<5)

[4435] {

[4436] a +=b;

[4437] b *=2;

[4438] x++;

[4439] }

[4440] This code takes 16 clock cycles to execute. One is required forthe initialisation of x and three for each execution of the body. Sincethe body is executed 5 times, this gives a total of 16 clock cycles.

[4441] Decision

[4442] if (a<b)

[4443] {

[4444] x=a;

[4445] }

[4446] else

[4447] {

[4448] x=b;

[4449] }

[4450] This code takes exactly one clock cycle to execute. Only one ofthe branches of the if statement is executed, either x=a or x=b. Each ofthese assignments takes one clock cycle. Notice again that no time istaken for the test because no assignment is made. A slightly differentexample is:

[4451] if (a>b)

[4452] {

[4453] x a;

[4454] }

[4455] Here, if a is not greater than b, there is no else branch. Thiscode therefore takes either 1 clock cycle if a is greater than b or noclock cycles if a is not greater than b.

[4456] Channels

[4457] Channel communications are more complex. The simplest example is:

[4458] par

[4459] {

[4460] link ! x;// Transmit

[4461] link ? y;// Receive

[4462] }

[4463] This code takes a single clock cycle to execute because both thetransmitting and receiving branches are ready to transfer at the sametime. All that is required is the assignment of x to y which, like allassignments, takes 1 clock cycle. A more complex example is:

[4464] par

[4465] {

[4466] {// Parallel branch 1

[4467] a=b;

[4468] c=d;

[4469] link ! x;

[4470] }

[4471] link ? y;// Parallel branch 2

[4472] Here, the first branch of the par statement takes three clockcycles to execute. However, the second branch of the par statement alsotakes three clock cycles to execute because it may wait for two cyclesbefore the transmitting branch is ready. The usage of clock cycles is asfollows: Cycle Branch 1 Branch 2 1 a = b; delay 2 c = d; delay 3 Channeloutput Channel input

[4473] This approach extends to all the other Handel-C statements. FIGS.58A and 58B illustrate a summary 5800 of statement timings, inaccordance with one embodiment of the present invention.

[4474] Avoiding Combinatorial Loops

[4475] Consider the following example:

[4476] while (x!=3);// WARNING!!

[4477] If x is modified in a parallel process then this loop should waitfor x to become 3 before allowing the program to continue. However, thiscode is not allowed in Handel-C because it generates a combinatorialloop in the logic because of the way that Handel-C expressions are builtto evaluate in zero clock cycles. This is easier to see if one writes itas:

[4478] while (x!=3)

[4479] {

[4480] // wait until x==3

[4481] }

[4482] This loop may be broken by changing the code to:

[4483] while (x!=3)

[4484] {

[4485] delay;

[4486] This loop takes no longer to execute than the other but does notcontain a combinatorial loop because of the clock cycle delay in theloop body. The Handel-C compiler may spots this form of error, insertthe delay statement, and generate a warning. It is considered betterpractice to include the delay statement in the code to make it explicit.Beware of code which may look correct but has the same error. Forexample:

[4487] while (x!=3)

[4488] {

[4489] if (y>z)

[4490] {

[4491] a++;

[4492] }

[4493] }

[4494] As seen above, this if statement may take zero clock cycles toexecute if y is not greater than z so even though this loop body doesnot look empty a combinatorial loop is still generated. Again, this ismore obvious written as

[4495] while (x!=3)

[4496] {

[4497] if (y>Z)

[4498] {

[4499] a++;

[4500] }

[4501] else

[4502] {

[4503] // do nothing

[4504] }

[4505] }

[4506] The solution in this example is to add the else part of the ifconstruct as follows:

[4507] while (x!=3)

[4508] {

[4509] if (y>z)

[4510] {

[4511] a++;

[4512] }

[4513] else

[4514] {

[4515] delay;

[4516] }

[4517] }

[4518] Similar problems occur with do...while loops and switchstatements in similar circumstances. In addition, for loops with noiteration step can cause combinatorial loops.

[4519] Parallel Access to Variables

[4520] As discussed earlier, Scope and variable sharing, the rules ofparallelism state that the same variable may not be accessed from twoseparate parallel branches. This rule is there to avoid resourceconflicts on the variables. However, if care is taken then this rule maybe relaxed to state that the same variable may not be assigned to morethan once on the same clock cycle but may be read as many times asrequired. The analysis presented in this section of the presentdescription allows the programmer to determine precisely when anassignment may take place and avoid such conflicts.

[4521] This relaxation allows some useful and powerful programmingtechniques. For example:

[4522] par

[4523] {

[4524] a=b;

[4525] b=a;

[4526] }

[4527] This code swaps the values of a and b in a single clock cycle.Since exact execution time may be run-time dependant, the Handel-Ccompiler cannot determine when two assignments are made to the samevariable on the same clock cycle. One should therefore check the code toensure that the relaxed rule of parallelism is still obeyed. Using thistechnique, a four place queue can be written:

[4528] while(1)

[4529] {

[4530] par

[4531] {

[4532] int x[3];

[4533] x[0]=in;

[4534] x[1]=x[0];

[4535] x[2]=x[1];

[4536] out=x[2];

[4537] }

[4538] }

[4539] Here, the value of out is the value of in delayed by 4 clockcycles. On each clock cycle, values may move one place through the xarray. FIG. 59 illustrates various I/O 5900 based on clock cycles, inaccordance with one embodiment of the present invention.

[4540] Multiple Simultaneous use of RAMs and ROMs

[4541] Beware of the following code:

[4542] x=y>z ? RamA[1]: RamA[2];

[4543] This code does not execute correctly because of the multiple useof the RAM in the expression.

[4544] The solution is to re-write the code as follows:

[4545] x=RamA[y>z ? 1: 2];

[4546] Here, there is only a single access to the RAM so the problemdoes not occur.

[4547] Detailed Timing Example

[4548] Here is an analyzed example that generates signals tied toreal-world constraints. The example used is the generation of signalsfor a real time clock. The signals required arc for microseconds,seconds, minutes and hours. The hardware generated may eventually bedriven from an external clock. In order to write the program, the rateof this clock may be known so a value of 5 MHz is assumed. The Handel-Cprogram is shown below.

[4549] The loop body takes one clock cycle to execute. The Countvariable is used to divide the clock by 5 to generate microsecondincrements. As each variable wraps round to zero, the next time step upis incremented.

[4550] void main(void)

[4551] {

[4552] unsigned 20 MicroSeconds;

[4553] unsigned 6 Seconds;

[4554] unsigned 6 Minutes;.

[4555] unsigned 16 Hours;

[4556] unsigned 3 Count;

[4557] par

[4558] {

[4559] Count=0;

[4560] MicroSeconds=0;

[4561] Seconds=0;

[4562] Minutes=0;

[4563] Hours=0;

[4564] }

[4565] while (1)

[4566] {

[4567] if (Count!=4)

[4568] Count++;

[4569] else

[4570] par

[4571] {

[4572] Count=0;

[4573] if (MicroSeconds!=999999)

[4574] Microseconds++;

[4575] else

[4576] par

[4577] {

[4578] MicroSeconds=0;

[4579] if (Seconds!=59)

[4580] Seconds++;

[4581] else

[4582] par

[4583] {

[4584] Seconds=0;

[4585] if (Minutes!=59)

[4586] Minutes++;

[4587] else

[4588] par

[4589] {

[4590] Minutes=0;

[4591] Hours++;

[4592] }

[4593] }

[4594] }

[4595] }

[4596] }

[4597] Time Efficiency of Handel-C Hardware

[4598] Handel-C requires that the clock period for a program is longerthan the longest path through combinatorial logic in the whole program.This means that, for example, once FPGA place and route has beencompleted, the maximum clock rate for the system can be calculated fromthe reciprocal of the longest path delay in the circuit. For example,suppose the FPGA place and route tools calculate that the longest pathdelay between flip-flops in a design is 70 ns. The maximum clock ratethat that circuit should be run at is then {fraction (1/70)} ns=14.3MHz. But what if this calculated rate is not fast enough for the systemperformance or real time constraints? This section deals withoptimizations that can be made to the program to reduce the longest pathdelay and increase the maximum possible clock rate.

[4599] Reducing Logic Depth

[4600] When designing Handel-C programs, it is important to rememberwhich operations combine to produce deep logic. Deep logic results inlong path delays in the final circuit so reducing logic depth shouldhelp to increase clock speed. Some guidelines will now be given forreducing logic depth.

[4601] 1. Division and modulus operators produce the deepest logic.Multiplication also produces deep logic. A single cycle divide, mod ormultiplier produces a large amount of hardware and long delays throughdeep logic so one should avoid using them wherever possible.

[4602] 2. Most common division and multiplications can be done with theshift operators. Also consider using a long multiplication with a loop,shift and add routine or a pipelined multiplier.

[4603] 3. Most common modulus operations can be done with the ANDoperator.

[4604] 4. Wide adders require deep logic for the carry ripple. Considerusing more clock cycles with shorter adders. For example, to reduce asingle, 8-bit wide adder to 3, narrower adders:

[4605] unsigned 8 x;

[4606] unsigned 8 y;

[4607] unsigned 5 temp1;

[4608] unsigned 4 temp2;

[4609] par

[4610] {

[4611] temp1=(0@(x<−4)) +(0@(y<−4));

[4612] temp2=(x \\4) +(y \\4);

[4613] }

[4614] x=(temp2+(0@temp1[4])) @ temp1[3:0];

[4615] 5. Avoid greater than and less than comparisons—they produce deeplogic. For example:

[4616] while (x<y)

[4617] {

[4618] ......

[4619] x++;

[4620] }

[4621] can be replaced with:

[4622] while (x!=y)

[4623] {

[4624] ......

[4625] x++;

[4626] }

[4627] The =<=and !<=comparisons produce much shallower logic althoughin some cases it is possible to remove the comparison altogether.Consider the following code:

[4628] unsigned 8 x;

[4629] x=0;

[4630] do

[4631] {

[4632] .....

[4633] x=x+1;

[4634] }while (x !=0);

[4635] This code iterates the loop body 256 times but it can bere-written as follows:

[4636] unsigned 9 x;

[4637] x=0;

[4638] do

[4639] {

[4640] ......

[4641] x=x+1;

[4642] } while (!x[8]);

[4643] By widening x by a single bit and just checking the top bit, onemay remove an 8-bit comparison.

[4644] 6. Reduce complex expressions into a number of stages. Forexample:

[4645] x=a +b +c +d +e +f +g +h

[4646] reduces to:

[4647] par

[4648] {

[4649] temp1=a +b;

[4650] temp2=c +d;

[4651] temp3=e +f;

[4652] temp4=g +h;

[4653] }

[4654] par

[4655] {

[4656] temp1=temp1 +temp2;

[4657] temp3=temp3 +temp4;

[4658] }

[4659] x=temp1 +temp3;

[4660] This code takes three clocks cycles as opposed to one but eachclock cycle is much shorter and so the rest of the circuit should bespeeded up by the faster clock rate permitted.

[4661] 7. Avoid long strings of empty statements. Empty statementsresult from, for example, missing else conditions from if statements.For example:

[4662] if (a>b)

[4663] x++;

[4664] if(b>c)

[4665] x++;

[4666] if (c>d)

[4667] x++;

[4668] if (d>e)

[4669] x++;

[4670] if (e<f)

[4671] x++;

[4672] If none of these conditions is met then all the comparisons maybe made in one clock cycle. By filling in the else statements withdelays, the long path through all these if statements can be split atthe expense of having each if statement take one clock cycle whether thecondition is true or not.

[4673] Pipelining

[4674] A classic way to increase clock rates in hardware is to pipeline.A pipelined circuit takes more than one clock cycle to calculate anyresult but can produce one result every clock cycle. The trade off is anincreased latency for a higher throughput so pipelining is onlyeffective if there is a large quantity of data to be processed—it is notpractical for single calculations. An example of a pipelined multiplieris given below.

[4675] unsigned 8 sum[8];

[4676] unsigned 8 a[8];

[4677] unsigned 8 b[8];

[4678] chanin inputa;

[4679] chanin inputb;

[4680] chanout output;

[4681] par

[4682] {

[4683] while(1)

[4684] inputa ? a[0];

[4685] while(1)

[4686] inputb ? b[0];

[4687] while(1)

[4688] output ! sum[7];

[4689] while(1)

[4690] {

[4691] par

[4692] {

[4693] macro proc level(x)

[4694] par

[4695] {

[4696] sum[x]=sum[x −1] +

[4697] ((a[x][0]==0) ? 0: b[x]);

[4698] a[x]=a[x −1] >>1;

[4699] b[x]=b[x −1] <<1;

[4700] }

[4701] sum[0]=((a[0][0]==0) ? 0 : b[0]);

[4702] level(1);

[4703] level(2);

[4704] level(3);

[4705] level(4);

[4706] level(5);

[4707] level(6);

[4708] level(7);

[4709] }

[4710] }

[4711] }

[4712] This multiplier calculates the 8 LSBs of the result of an 8-bitby 8-bit multiply using long multiplication. The multiplier produces oneresult per clock cycle with a latency of 8 clock cycles. This means thatalthough any one result takes 8 clock cycles, one gets a throughput of 1multiply per clock cycle. Since each pipeline stage is very simple,combinatorial logic is shallow and a much higher clock rate is achievedthan would be possible with a complete single cycle multiplier. At eachclock cycle, partial results pass through each stage of the multiplierin the sum array. Each stage adds on 2 n multiplied by the b operand ifrequired. The LSB of the a operand at each stage tells the multiplystage whether to add this value or not. Stages are generated with amacro procedure to avoid tedious repetition of code.

[4713] Operands are fed in on every clock cycle through a[0] and b[0].Results appear 8 clock cycles later on every clock cycle throughsum[7]..11 Targeting hardware.

[4714] Introduction

[4715] The previous sections have covered most aspects of writingHandel-C programs. What has not yet been discussed is how to get datainto and out of those programs. A major advantage of the custom hardwarethat can be produced with Handel-C is its ability to interface directlywith external components such as RAM, custom and non-custom buses. Thissection of the present description deals with getting data into and outfrom the Handel-C program. It begins with a discussion of using thesimulator provided with the Handel-C compiler to ensure that the programis correct and then describes interfacing with real hardware devicesconnected to the pins of the chip containing the hardware. The simulatorexecutes Handel-C programs on the compiling machine without anyadditional hardware. It allows output to the screen or a file and inputfrom the keyboard or a file. It is a powerful tool that allows programsto be tested thoroughly before custom hardware is manufactured. While nospecific hardware platform is detailed here, a number of examples aregiven of interfacing to theoretical hardware.

[4716] Interfacing with the Simulator

[4717] This section of the present description covers how the programcommunicates with the simulator. This enables one to debug with realdata. Code examples are set forth herein. Communication with thesimulator takes place over channels. They are declared using thekeywords chanin and chanout. It is assumed that simulation channelsnever block and may always complete a transfer in one clock cycle.

[4718] Simulator channels are declared using chanin and chanout insteadof chan

[4719] Transfers Over Channels

[4720] The special channels chanin and chanout may be defined forinputting information from the simulator and outputting information backto the simulator. These channels are normally connected to files,although an unconnected channel that outputs data to the simulator maybe displayed in the debug window. For example:

[4721] chanin unsigned Input with {infile=“../Data/source.dat”};

[4722] chanout unsigned Output;

[4723] input ? x;

[4724] output! y;

[4725] This example declares two channels: one for input from thesimulator and one for output to the simulator. The input channelconnects to a file managed by the simulator; the output channel connectsto the simulator's standard output (the debug window in the Handel-CGUI) Standard channel communication statements can then be used totransfer data. One can declare multiple channels for input and output.For example:

[4726] chanin int 8 input_(—)1 with

[4727] {infile=“../Data/source_(—)1.dat”};

[4728] chanin int 16 input_(—)2 with

[4729] {infile=“../Data/source_(—)2.dat”};

[4730] chanout unsigned 3 output_(—)1;

[4731] chanout char output_(—)2;

[4732] input_(—)1 ? a;

[4733] input_(—)2 ? b;

[4734] output_(—)1 ! (unsigned 3)(((0@ a) +b)<- 3);

[4735] output_(—)2 ! a;

[4736] When simulated, such a program displays the name of channelsbefore outputting their value on the simulating computer screen.

[4737] Simulator Input File Format

[4738] The data input file should have one number per line separated bynewline characters (either DOS or Unix format text files may be used).Each number may be in any format normally used for constants byHandel-C. For example:

[4739] 56

[4740] 0x34

[4741] 0654

[4742] 0b001001

[4743] Block Data Transfers

[4744] The Handel-C simulator has the ability to read data from a fileand write results to another file. For example:

[4745] chanin int 16 input with {infile=“in.dat”}:

[4746] chanout int 16 output with {outfile=“out.dat”};

[4747] void main (void)

[4748] {

[4749] while (1)

[4750] {

[4751] int value;

[4752] input ? value;

[4753] output ! value+1;

[4754] }

[4755] }

[4756] This program reads data from the file in.dat and writes itsresults to the file out.dat. If the in.dat file consists of:

[4757] 56

[4758] 0x34

[4759] 0654

[4760] 0b001001

[4761] the out.dat may contain the decimal results as follows:

[4762] 57

[4763] 53

[4764] 429

[4765] 10

[4766] This feature allows algorithms to be debugged and tested withoutneeding to build actual hardware. For example, an image processingapplication may store a source image in a file and place its results ina second file. All that need be done outside the Handel-C compiler is aconversion from the image (e.g. JPEG file) into the text file taken bythe simulator and a conversion back from the output file to an imageformat. The results can then be viewed and the correct operation of theHandel-C program confirmed.

[4767] Targeting FPGA Devices

[4768] The Handel-C language is designed to target real hardwaredevices. One may supply some important pieces of information to thecompiler to allow it to do this. These are: the FPGA family and partthat the design may be implemented in the location of a clock source TheFPGA part details are supplied through the Project>Settings dialog inthe GUI (Graphical User Interface). They can also be supplied to thecommand line compiler using the set statement. Ultimately, thisinformation is passed to the FPGA place and route tool to inform it ofthe device it should target. The clock source is specified using the‘set’ command.

[4769] Locating the Clock

[4770] Since each Handel-C main( ) code block generates synchronoushardware, a single clock source is required for each one. The clock isnormally provided on one of the external pins of the FPGA but may alsobe generated internally on Xilinx 4000 devices. The general syntax ofthe clock specification is:

[4771] set clock=Location;

[4772]FIG. 60 illustrates a table 6000 showing the various locations, inaccordance with one embodiment of the present invention.

[4773] Examples of clocks taken from external device pins are:

[4774] set clock external “P35”;

[4775] set clock=external_divide “P35” 3;

[4776] set clock=external_divide 3;.

[4777] The first of these examples specifies a clock taken from pin P35.The second of these examples specifies a clock taken from pin P35 whichis divided on the FPGA by a factor of 3. The third option shows a clockdivided by 3 with no pin number specified. When the pin number isomitted, the place and route tools may choose an appropriate pin.Omitting pin specifications can speed up the design. Examples of clockstaken from the Xilinx 4000 series internal clock generator are:

[4778] set clock=internal “F8M”;

[4779] set clock=internal_divide “F8M” 3;

[4780] Currently, the frequency of the internal clock may take one ofthe following values: Specification String Frequency “F15” 15 Hz “F490”490 Hz “F16K” 16 kHz “F500K” 500 kHz “F8M” 8 MHz

[4781] Note that the tolerance for these values is −50% to +25% so oneshould not rely on the internal clock being at exactly thesefrequencies. Internal clocks are only supported on Xilinx 4000 seriesparts. The clock division specified with the internal_divide andexternal_divide keywords may be a constant integer.

[4782] Targeting Specific Devices via the Command Line

[4783] If one is not using the GUI to specify the target device, he orshe may insert lines in the code to specify it. In order to target aspecific FPGA, the compiler may be supplied with the FPGA part number.Ultimately, this information is passed to the FPGA place and route toolto inform it of the device it should target. Targeting devices is in twoparts: specifying the target family and the target device. The generalsyntax is:

[4784] set family<=Family;

[4785] set part<=Chip Number;

[4786]FIG. 61 illustrates the various family names 6100, in accordancewith one embodiment of the present invention.

[4787] The part string is the complete Xilinx or Altera device string.For example:

[4788] set family<=Xilinx4000E;

[4789] set part=“4010EPC84-1”;

[4790] This instructs the compiler to target a XC4010E device in aPLCC84 package. It also specifies that the device is a −1 speed grade.This last piece of information is required for the timing analysis ofthe design by the Xilinx tools.

[4791] The family is used to inform the compiler of which special blocksit may generate.

[4792] To target Altera Flex 10K devices:

[4793] set family=Altera10K;

[4794] set part “EPF10K20RC240-3”;

[4795] This instructs the compiler to target an Altera Flex 10K20 devicein a RC240 package. It also specifies that the device is a −3 speedgrade. This last piece of information is required for the timinganalysis of the design by the Altera Max Plus II or Quartus tools. Notethat when performing place and route on the resulting design, the deviceand package may also be selected via the menus in the Max Plus IIsoftware.

[4796] Use of RAMs and ROMs with Handel-C

[4797] Handel-C provides support for interfacing to on-chip and off-chipRAMs and ROMs using the ram and rom keywords. One can specify RAMs andROMs external to the Handel-C code by using the ports specificationkeyword. One can control the timing for read/write cycles by usingspecification keywords that define the relationship between the RAMstrobe and the Handel-C clock.

[4798] The usual technique for specifying timing in synchronous andasynchronous RAM is to have a fast external clock which is divided downto provide the Handel-C clock and used directly to provide the pulses tothe RAM

[4799] Asynchronous RAMs

[4800] There are three techniques for timing asynchronous RAMs,depending on the clock available

[4801] 1. Fast external clock. Use the Handel-C westart and welengthspecifications to position the write strobe

[4802] 2. External clock at the same speed as the Handel-C clock. Usemultiple reads to give the RAM enough time to respond.

[4803] 3. Use the wegate specification to position the write enablesignal within the Handel-C clock

[4804] Fast External Clock

[4805] If the external clock is faster than the internal clock (i.e. thelocation of the clock is internal_divide or external_divide with adivision factor greater than 1) then Handel-C can generate a writestrobe for the RAM which is positioned within the Handel-C clock cycle.This is done with the westart and welength specifications. For example:

[4806] set clock=external_divide “P78”4;

[4807] rain unsigned 6 x[34] with {westart=2,

[4808] welength=1};

[4809] The write strobe can be positioned relative to the Handel-C clockcycle by half cycle lengths of the external (undivided) clock. The aboveexample starts the pulse 2 whole external clock cycles into the Handel-Cclock cycle and gives it a duration of 1 external clock cycle. Since theexternal clock is divided by a factor of 4, this is equivalent to astrobe that starts half way through the internal clock cycle and has aduration of one quarter of the internal clock cycle. FIG. 62 illustratesa timing diagram showing a signal 6200, in accordance with oneembodiment of the present invention.

[4810] Timing Diagram: Positioned Write Strobe

[4811] This timing allows half a clock cycle for the RAM setup time onthe address and data lines and one quarter of a clock cycle for the RAMhold times. This is the recommended way to access asynchronous RAMs.

[4812] Same Rate External Clock

[4813] This method uses multiple Handel-C RAM accesses to meet the setupand hold times of the RAM.

[4814] ram unsigned 6 x[34];

[4815] Dummy=x[3];

[4816] x[3]=Data;

[4817] Dummy=x[3];

[4818] This code holds the address constant around the RAM write cycle,enabling a write to an asynchronous RAM.

[4819] Undivided External Clock

[4820] The third method of accessing asynchronous RAMs is a compromisebetween the two previous methods. wegate is used with an undividedexternal clock and keeps the write strobe in the first or second half ofthe clock cycle. It is still necessary to hold the address constanteither in the clock cycle before or in the clock cycle after the access.For example:

[4821] ram unsigned 6 x[34] with {wegate=1};

[4822] x[3]=Data;

[4823] Dummy=x[3];

[4824] This places the write strobe in the second half of the clockcycle (use a value of −1 to put it in the first half) and holds theaddress for the clock cycle after the write. The RAM therefore has halfa clock cycle of setup time and one clock cycle of hold time on itsaddress lines.

[4825] Synchronous RAMs

[4826] Handel-C timing semantics require that any assignment takes oneclock cycle. SSRAMs have a latency of at least one clock cycle. Toenable the SSRAM timings to fit with the Handel-C timing constraints,Handel-C uses an independent fast clock (RAMCLK). The generation of thisclock requires the use of a fast external clock (CLK), divided toprovide the Handel-C clock (HCLK).

[4827] The fast clock's pulses can then be placed to clock the SSRAMwithin a single Handel-C clock tick. The RAMCLK can be carried to anexternal SSRAM using the clk specification.

[4828] Handel-C supports ZBT-compatible (Zero Bus Turnaround)flow-through and pipelined output devices. DDR (double data rate) andQDR (quad data rate) devices are not supported.

[4829] The Handel-C compiler checks the block specification to find outwhat type of RAM is being built and generates the appropriatewrite-enable signal (e.g. active low for ZBT SSRAM devices andactive-high for block RAMs within Xilinx Virtex chips).

[4830] SSRAM Read and Write Cycles

[4831] Most inputs to SSRAMs are captured on the rising edge of theinput clock. During a read cycle there is a latency of at least oneclock cycle between an address being captured at the input and databecoming available at the output. This is also true for the write cyclein many devices: an address is captured on one clock cycle, and data onthe next.

[4832]FIG. 63 illustrates a timing diagram showing a SSRAM read andwrite 6300, in accordance with one embodiment of the present invention.

[4833] Specifying the Timing

[4834] One can place the RAM clock pulses at different points within theHandel-C clock in the same way that write-enable strobes can bespecified for asynchronous RAM devices. The SSRAM clock (RAMCLK) isgenerated from the fast clock (CLK) according to the Handel-Cspecifications: rclkpos, wclkpos and clkpulselen. These specificationscan be in whole or half cycles of the external clock.

[4835] rclkpos specifies the positions of the clock cycles of clockRAMCLK for a read cycle. These positions are specified in terms ofcycles and half-cycles of CLK, counting forwards from a HCLK risingedge.

[4836] wclkpos specifies the positions of the clock cycles of RAMCLK fora write cycle. These are also counted forward from an HCLK rising edge.

[4837] clkpulselen specifies the length of the RAMCLK pulses in CLKcycles. This is specified once per RAM. It applies to both the read andwrite clocks.

[4838] Timing Diagram: SSRAM Read Cycle Using Generated RAMCLK

[4839]FIG. 64 illustrates a timing diagram showing a SSRAM read cycleusing generated RAMCLK 6400, in accordance with one embodiment of thepresent invention. The pulse positions and lengths are specified incycles and half-cycles of CLK. The westart and welength specs are usedto place the write enable strobe where it is required.

[4840] Examples

[4841] Flow-through SSRAM

[4842] This example code generates the hardware shown below. It is alsoapplicable for reading from block RAMs in Xilinx and Altera FPGAs.

[4843] ram unsigned 18 FlowBank[1024] with {block=1,

[4844] westart=2,

[4845] welength=1,

[4846] rclkpos={1.5},

[4847] wclkpos={2.5, 3.5},

[4848] clkpulselen=0.5};

[4849]FIG. 65 illustrates a timing diagram showing read-cycle from aflow-through SSRAM within a Handel-C design 6500, in accordance with oneembodiment of the present invention.

[4850] The rising HCLK edge at t0 initiates the read cycle. Some timelater, the address A1 is set up, which is sampled somewhere in themiddle of the HCLK cycle: t0+1.5 in this case. By the time the next HCLKrising edge occurs at t1, the data is available for reading. The cyclecompletes within one Handel-C clock cycle.

[4851] Write Cycle for a Flow-through SSRAM

[4852] Flow-through SSRAMs perform a “late” write cycle; the data isclocked in one clock cycle after the address is sampled. FIG. 66illustrates a timing diagram showing complete write cycle 6600, inaccordance with one embodiment of the present invention.

[4853] The HCLK rising edge at t0 initiates the write cycle, causing theADDRESS and DATAIN signals to change. Two cycles of RAMCLK are needed toclock the new data into the RAM at the specified address: the first tosample the address, the second to sample the data. However, since it isnot expected to read from the RAM's output, one can wait until the lastpossible moment. In this case, the two rising edges of RAMCLK occur att0+2.5 and t0+3.5.

[4854] The write enable signal may be low during the rising edge ofRAMCLK that samples the address, but not during the one that samples thedata. This can be done by setting westart and welength as shown. Theentire cycle completes within a single Handel-C clock cycle.

[4855] Pipelined-output SSRAM

[4856] This example code generates the hardware shown below

[4857] ram unsigned 18 PipeBank[1024] with {block=1,

[4858] westart=1.5,

[4859] welength=1,

[4860] rclkpos={1.5, 2.5},

[4861] wclkpos={2, 3, 4},

[4862] clkpulselen=0.5};

[4863]FIG. 67 illustrates a timing diagram showing complete read cycle6700, in accordance with one embodiment of the present invention. Thisread cycle is very similar to that for a flow through RAM. The risingHCLK edge at t0 initiates the read cycle. Some time later, the addressA1 is set up, which is sampled somewhere near the middle of the HCLKcycle: (t0+1.5 in this case). The RAM contents at address A1 are thenpiped to the RAM's output register; it may be made available at the RAMoutput. A second RAMCLK pulse (at t0+2.5 in this case) is used to dothis. By the time the next HCLK rising edge occurs at t1, the data isavailable for reading by the Handel-C design. The cycle completes withinone Handel-C clock cycle.

[4864] Write Cycle for a Pipelined-output SSRAM

[4865] Pipelined-output SSRAMs perform a “late-late” write cycle. Thismeans that data is written to memory two clock cycles after the addressis sampled. FIG. 68 illustrates a timing diagram showing complete cycle6800, in accordance with one embodiment of the present invention. TheHCLK rising edge at t0 initiates the write cycle, causing the ADDRESSand DATAIN signals to change. Three cycles of RAMCLK are needed to clockthe new data into the RAM at the specified address: the first to samplethe address and the third to sample the data. Since one may not readfrom the RAM on a write strobe, he or she can sample the data as late aspossible to give the circuit maximum time to set up the data. In thiscase, the three rising edges of RAMCLK occur at t0+2.0, t0+3.0 andt0+4.0. The write enable signal may be low during the rising edge ofRAMCLK that samples the address, but not during the one that samples thedata. This can be done by setting westart and welength as shown. Theentire cycle completes within a single Handel-C clock cycle.

[4866] Using On-chip RAMs in Xilinx Devices

[4867] Xilinx 4000 series devices can implement RAMs and ROMs in thelook up tables on the device. Handel-C supports the synchronous RAMs onthe 4000E, 4000EX, 4000L, 4000XL, 4000XV and Virtex series partsdirectly simply by declaring a RAM or ROM in the way described earlier.For example:

[4868] ram unsigned 6 x[34];.

[4869] This may declare a RAM with 34 entries, each of which is 6 bitswide.

[4870] Using On-chip RAMs in Altera Devices

[4871] On-chip RAMs in Altera Flex10K devices use the EAB structures.These blocks can be configured in a number of data width/address widthcombinations. When writing Handel-C programs, one may be careful not toexceed the number of EAB blocks in the target device or the design maynot place and route successfully. While it is possible to use RAMs thatdo not match one of the data width/address width combinations, EAB spacemay be wasted by such a RAM. As with Xilinx devices, the RAM blocks inFlex 10K parts can be configured to be either synchronous orasynchronous.

[4872] Synchronous Access

[4873] By default, Handel-C may use a synchronous access by utilizingthe falling edge of the clock as the input clock signal to the RAM. Thisis the recommended method for using RAMs.

[4874] Asynchronous Access

[4875] If one uses one of the westart, welength or wegate specificationsdescribed in the previous section, the Handel-C compiler may generate anasynchronous RAM. This may help with the timing characteristics of thedesign.

[4876] Initialisation

[4877] RAM/ROM initialisation files with a .mif extension may begenerated on compilation to feed into the Max Plus II software. Thisprocess is transparent as long as they are in the same directory as theEDIF (.edf extension) file generated by the Handel-C compiler.

[4878] Using External RAMs

[4879] Asynchronous RAMs

[4880] Handel-C provides support for accessing off-chip static RAMs inthe same way as one access internal RAMs. The syntax for an external RAMdeclaration is:

[4881] ram Type Name[Size] with {

[4882] offchip=1,

[4883] data=Pins,

[4884] addr=Pins,

[4885] we=Pins,

[4886] oe=Pins,

[4887] cs=Pins};

[4888] For example, to declare a 16Kbyte by 8-bit RAM:

[4889] ram unsigned 8 ExtRAM[16384] with {

[4890] offchip=1,

[4891] data={“P1”, “P2”, “P3”, “P4”,

[4892] “P5”, “P6”, “P7”, “P8”},

[4893] addr={“P9”, “P10”, “P 11”, “P12”,

[4894] “P13”, “P14”, “P 15”, “P 16”,

[4895] “P 17”, “P 18”, “P 19”, “P20”,

[4896] “P21”, “P22”},

[4897] we={“P23”},

[4898] oe={“P24”},

[4899] Cs={“P25”}};

[4900] Note that the lists of address and data pins are in the order ofmost significant to least significant. It is possible for the compilerto infer the width of the RAM (8 bits in this example) and the number ofaddress lines used (14 in this example) from the RAM's usage. However,this is not recommended since this declaration deals with real externalhardware which has a fixed definition. Accessing the RAM is the same asfor accessing internal RAM. For example:

[4901] ExtRAM[1234]=23;

[4902] y=ExtRAM[5678];

[4903] Similar restrictions apply as with internal RAM—only one accessmay be made to the RAM in any one clock cycle. The compiled hardwaregenerates the following cycle for a write to external RAM. FIG. 69illustrates a timing diagram showing a cycle for a write to external RAM6900, in accordance with one embodiment of the present invention. FIG.70 illustrates a timing diagram showing a cycle for a read from externalRAM 7000, in accordance with one embodiment of the present invention.

[4904] This cycle may not be suitable for the RAM device in use. Inparticular, asynchronous static RAM may not work with the above cycledue to setup and hold timing violations. For this reason, the westart,welength and wegate specifications may also be used with external RAMdeclarations.

[4905] Fast External Clock Example

[4906] For example, to declare a 16Kbyte by 8-bit RAM:

[4907] set clock=external_divide “P99”4;

[4908] ram unsigned 8 ExtRAM[16384] with {

[4909] offchip=1,

[4910] westart=2,

[4911] welength=1,

[4912] data={“P1”, “P2”, “P3”, “P4”,

[4913] “P5”, “P6”, “P7”, “P8”},

[4914] addr={“P9”, “P10”, “P11”, “P12”,

[4915] “P13”, “P14”, “P15”, “16”,

[4916] “P17”, “P18”, “P19”, “P20”,

[4917] “P21”, “P22”},

[4918] we={“P23”},

[4919] oe={“P24”},

[4920] cs={“P25}};

[4921]FIG. 71 illustrates a timing diagram showing a cycle for a writeto external RAM 7100, in accordance with one embodiment of the presentinvention. FIG. 72 illustrates a timing diagram showing a cycle for aread from external RAM 7200, in accordance with one embodiment of thepresent invention.

[4922] The compiled hardware generates the following cycle for a writeto external RAM.

[4923] The compiled hardware generates the following cycle for a readfrom external RAM:

[4924] Accessing the RAM is the same as for accessing internal RAM. Forexample:

[4925] ExtRAM[1234]=23;

[4926] y=ExtRAM[5678];

[4927] Similar restrictions apply as with internal RAM—only one accessmay be made to the RAM in any one clock cycle.

[4928] Wegate Example

[4929] wegate specification may be used when a multiplied clock is notavailable.

[4930] For example, to declare a 16 Kbyte by 8-bit RAM:

[4931] ram unsigned 8 ExtRAM[16384] with {

[4932] offchip=1,

[4933] wegate=1,

[4934] data “P”,“P2”,“P3”,“P4”,

[4935] “P5”,“P6”,“P7”,“P8”},

[4936] addr={“P9”,“P10”,“P11”,“P12”,

[4937] “P13”,“P14”, “P15”, “P16”,

[4938] “P17”,37 P18”,“P19”,“P20”,

[4939] “P21”,“P22”},

[4940] we={“P23”},

[4941] oe={“P24”},

[4942] cs={“P25”}};

[4943]FIG. 73 illustrates a timing diagram showing a cycle for a writeto external RAM 7300, in accordance with one embodiment of the presentinvention. FIG. 74 illustrates a timing diagram showing a cycle for aread from external RAM 7500, in accordance with one embodiment of thepresent invention.

[4944] Accessing the RAM is the same as for accessing internal RAM. Forexample:

[4945] ExtRAM[3]=Data;

[4946] Dummy=ExtRAM[3];

[4947] Similar restrictions apply as with internal RAM—only one accessmay be made to the RAM in any one clock cycle. Note that the timingdiagram above may violate the hold time for some asynchronous RAMdevices. If the delay between rising clock edge and rising write enableis longer than the delay between rising clock edge and the change indata or address then corruption in the write may occur in these devices.The two cycle access does not solve this problem since it is notpossible to hold the data lines constant beyond the end of the clockcycle. If this causes a problem then a multiplied external clock may beused as described above.

[4948] Using the wegate specification may violate the hold time for someasynchronous RAM devices.

[4949] Synchronous RAMs

[4950] Off-chip synchronous SRAMs can be specified in exactly the sameway as on-chip synchronous SRAMs, with the addition of the clkspecification. clk specifies the pin on which the generated RAMCLK mayappear, when the SSRAM in question is external (offchip=1).

[4951] Example

[4952] macro expr addresspins={Pin List . . . };

[4953] macro expr datapins={Pin List . . . };

[4954] macro expr cspins={Pin List . . . };

[4955] macro expr wePins={Pin List . . . };

[4956] macro expr oepins={Pin List . . . };

[4957] macro expr clkpins={Pin List . . . };

[4958] ram unsigned 32 ExtBank[1024] with {offchip=1,

[4959] addr=addressPins,

[4960] data=datapins,

[4961] cs=csPins,

[4962] we=wepins,

[4963] oe=oePins,

[4964] westart=2,

[4965] welength=1,

[4966] rclkpos={1.5, 2.5},

[4967] wclkpos={1.5, 2.5, 3.5},

[4968] clkpulselen=0.5,

[4969] clk=clkPins};

[4970] Using External ROMs

[4971] An external ROM is declared as an external RAM with an emptywrite enable pin list. For example:

[4972] ram unsigned 8 ExtROM[16384] with {

[4973] offchip=1,

[4974] data={“P1”, “P2”, “P3, P4”,

[4975] “P5”, “P6”, “P7”, “P8”56 ,

[4976] addr={“P9”, “P10”, “P11”, “P12”,

[4977] “P13”, “P14”,“P15”, “P16”,

[4978] “P17”, “P18”, “P19”, “P20”,

[4979] “P21”, “P22”},

[4980] we={ },

[4981] oe={“P24”},

[4982] cs={P25}};

[4983] Note that no westart, welength or wegate specification isrequired since there is not a write strobe signal on a ROM device.

[4984] Connecting to RAMs in Foreign Code

[4985] One can create ports to connect to a RAM by using the ports=1specification to the memory definition. This may generate VHDL or EDIFwires which can be connected to a component created elsewhere. The portsspecification cannot be used in conjunction with the offchip=1specification, but all other specifications may apply. The interfacegenerated may have separate read (output) and write (data) ports, writeenable, data enable and clock wires. This ensures that it can beconnected to any device. Pin names provided in the addr, data, cs, we,oe, and clk specifications may be passed through to the generated EDIF.They are not passed through to VHDL, since VHDL interfaces are generatedas n-bit wide buses rather than n 1-bit wide wires. This means that itis ambiguous to specify a separate identifier for each wire If they areused when compiling to VHDL, the compiler issues a warning.

[4986] A clock port may always be generated.

[4987] If one uses the ports specification with an MPRAM, a separateinterface may be generated for each port.

[4988] Examples

[4989] Example 1: Generating an Interface to a Foreign Code RAM.

[4990] // Pin name specifications have been commented out

[4991] set family=Xilinx4000XV;

[4992] set part=“V1000BG560-4”;

[4993] set clock=external “C1”;

[4994] macro expr dataPins={“D1”, “D2”, “D3”, “D4”};

[4995] macro expr addrPins={“A1”, “A2”};

[4996] macro expr wePins={“WE1”};

[4997] macro expr csPins={“CS1};

[4998] macro expr oePins={“OE1};

[4999] unsigned 4 a;

[5000] ram unsigned 4 rax[4] with {ports=1/*, data=dataPins,addr=addrPins, we=

[5001] wePins, Cs=csPins, oe=oePins*/};

[5002] void main(void)

[5003] {

[5004] static unsigned 2 i=0;

[5005] while(1)

[5006] {

[5007] par

[5008] {

[5009] i++;

[5010] a++;

[5011] rax[i]=a;

[5012] }

[5013] a=rax[i];

[5014] }

[5015] }

[5016] The declaration of rax would produce wires

[5017] rax_SPPort_addr<0>//Address

[5018] rax_SPPort_addr<1>

[5019] rax_SPPort_data_in<0>//Data In

[5020] rax_SPPort_data_in<1>

[5021] rax_SPPort_data_in<2>

[5022] rax_SPPort_data_in<3>

[5023] rax_SPPort_data_out<0>//Data Out

[5024] rax_SPPort_data_out<1>

[5025] rax_SPPort_data_out<2>

[5026] rax_SPPort_data_out<3>

[5027] rax_SPPort_data_en//Data Enable

[5028] rax_SPPort_clk//Clock

[5029] rax_SPPort_Cs//Chip Select

[5030] rax_SPPort_oe//Output Enable

[5031] rax_SPPort_we//Data In.

[5032] Example 1: Generating an Interface to a Foreign Code MPRAM.

[5033] //Pin name specifications have been commented out

[5034] set family=Xilinx4000XV;

[5035] set part=“V1000BG560-4”;

[5036] set clock=external “C1”;

[5037] macro expr dataPins={“D1”, “D2”, “D3”, “D4”};

[5038] macro expr addrPins={“A1”, “A2”};

[5039] macro expr wePins={“WE1”};

[5040] macro expr csPins={“CS1”};

[5041] macro expr oePins {“OE1”};

[5042] unsigned 4 a;

[5043] mpram Mpaz

[5044] {

[5045] wom unsigned 4 wox[4];

[5046] rom unsigned 4 rox[4];

[5047] } mox with {ports=1/*, data=dataPins, addr=addrPins, we=wePins,cs=

[5048] csPins, oe=oePins*/};

[5049] void main(void)

[5050] {

[5051] static unsigned 2 i=0;

[5052] while(1)

[5053] {

[5054] par

[5055] {

[5056] i++;

[5057] a++;

[5058] mox.wox[i]=a;

[5059] }

[5060] a=mox.rox[i];

[5061] }

[5062] }

[5063] Using Other RAMs

[5064] The interface to other types of RAM such as DRAM should bewritten by hand using interface declarations described in the followingsections. Macro procedures can then be written to perform complex oreven multi-cycle accesses to the external device.

[5065] Interfacing with External Hardware and Logic

[5066] While the simulator allows debugging of Handel-C programs, thereal target of the compiler is hardware. It is therefore essential thatthe compiler can generate hardware that interfaces with externalcomponents. These next sections detail the building blocks of suchhardware interfaces. All off-chip accesses are based on the idea of abus which is just a collection of external pins. Handel-C provides theability to read the state of pins for input from the outside world andset the state of pins for writing to the outside world. Tri-state busesare also supported to allow bi-directional data transfers through thesame pins. The pins used may be defined in Handel-C by using the dataspecification. If this is omitted, the pins may be left unconstrainedand can be assigned by the place and route tools. Note that Handel-Cprovides no information about the timing of the change of state of asignal within a Handel-C clock cycle. Timing analysis is available fromthe FPGA manufacturer's place-and-route tools. Handel-C programs canalso interface to external logic (other Handel-C programs, programswritten in VHDL etc.) by using user-defined interfaces or Handel-Cports.

[5067] Interfaces

[5068] All interfaces other than RAMs are declared with the interfacekeyword. The general syntax of interfaces is as follows: interfaceSort(Types) Name(Args) with {Specs}; Here, the Sort field specifies whatsort of interface is required, Types describes the types of valuesassociated with objects coming from the interface, Name specifies anidentifier for the interface, Args specifies any parameters that theinterface may require and Specs give hardware details of the interfacesuch as chip pin numbers. Further details of the interface syntax wereprovided earlier.

[5069]FIG. 75 is a table of pre-defined interface sorts 7500, inaccordance with one embodiment of the present invention.

[5070] Reading from External Pins

[5071] The bus_in interface sort allows Handel-C programs to read fromexternal pins. Its general usage is:

[5072] interface bus_in(typeportName) Name()

[5073] with {data={Pin List}};

[5074] A specific example is:

[5075] interface bus_in(int 4 To) InBus( ) with {data={“P1”, “P2”, “P3”,“P4”}};

[5076] This declares a bus connected to pins P1, P2, P3 and P4 where pinP1 is the most significant bit and pin P4 is the least significant bit.Reading the bus is performed by accessing the identifier NameportName asa variable which may return the value on those pins at that clock edge.For example:

[5077] int 4 x;

[5078] x=InBus.To;

[5079] This sets the variable x to the value on the external pins. Thetype of InBus.To is int 4 as specified in the type list after the bus_inkeyword.

[5080] If no input port name is given, the port name defaults to in.

[5081] Registered Reading From External Pins

[5082] The bus_latch_in interface sort is similar to the bus_ininterface sort but allows the input to be registered on a condition.This may be required to sample the signal at particular times. Itsgeneral usage is:

[5083] interface bus_latch_in(typeportName)

[5084] Name(type conditionPortName=Condition) with {data=(Pin List}};.

[5085] Its usage is exactly like the bus_in interface sort except thatCondition specifies a signal that is used to clock the input registersin the FPGA. The rising edge of this signal clocks the external signalinto the internal value. For example:

[5086] int 1 get;

[5087] int4 x;

[5088] interface bus_latch_in(int 4 To)

[5089] InBus(int 1 condition=get)

[5090] with {data={“P1”, “P2”, “P3”, “P4”}};

[5091] get=0;

[5092] get=1; //Register the external value

[5093] x=InBus.To; //Read the registered value

[5094] Clocked Reading From External Pins

[5095] The bus_clock_in interface sort is similar to the bus_ininterface sort but allows the input to be clocked continuously from theHandel-C global clock. This may be required to synchronize the signal tothe Handel-C clock. Its general usage is:

[5096] interface bus_clock_in(typeportName) Name( )

[5097] with {data={Pin List}};

[5098] Its usage is exactly like the bus_in interface sort. The risingedge of the Handel-C clock clocks the external signal into the internalvalue. For example:

[5099] interface bus_clock_in(int 4 InTo) InBus( ) with

[5100] {data={“P1”, “P2”, “P3”, “P4”}};

[5101] x=InBus.InTo; // Read flip-flop value

[5102] Writing to External Pins

[5103] The bus_out interface sort allows Handel-C programs to write toexternal pins. Its general usage is:

[5104] interface bus_out( ) Name(typeportName=Expression)

[5105] with {data={Pin List}};

[5106] A specific example is:

[5107] interface bus_out( ) OutBus(int 4 OutPort=x+y)

[5108] with {data=

[5109] {“P1”, “P2”, “P3”, “P4”}};

[5110] This declares a bus connected to pins 1, 2, 3 and 4 where pin 1is the most significant bit and pin 4 is the least significant bit. Thevalue appearing on the external pins is the value of the expression x+yat all times.

[5111] Bi-directional Data Transfer

[5112] The bus₁₃ ts interface sort allows Handel-C programs to performbidirectional off-chip communications via external pins. Its generalusage is:

[5113] interface bus_ts (type inPortName)

[5114] Name(type outPortName=Value,

[5115] type conditionPortName=Condition)

[5116] with {data={Pin List}};

[5117] Here, Value and Condition are two expressions. Value refers tothe value to output on the pins and Condition refers to the conditionfor driving the pins. When the second expression is non-zero (i.e.true), the value of the first expression is driven on the pins. When thevalue of the second expression is zero, the pins are tri-stated and thevalue of the external bus can be read using the identifierName.inPortName in much the same way that bus_in interfaces are read. IfinPortName is not defined, the port name defaults to in.

[5118] A specific example is:

[5119] int 1 condition;

[5120] int 4 x;

[5121] interface bus_ts(int 4 read)

[5122] BiBus(int write=x+1,

[5123] int 1 enable=condition)

[5124] with {data={“P1”, “P2”, “P3”, “P4”}};

[5125] condition=0; // Tri-state the pins

[5126] x=BiBus.read; // Read the value

[5127] condition=1; // Drive x+1 onto the pins

[5128] This example reads the value of the external bus into variable xand then drives the value of x+1 onto the external pins. Take care whendriving tri-state buses that the FPGA and another device on the buscannot drive simultaneously as this may result in damage to one or bothof them.

[5129] Bi-directional Data Transfer with Registered Input

[5130] The bus_ts_latch_in interface sort allows Handel-C programs toperform bidirectional off-chip communications via external pins withinputs registered on a condition. Its general usage is:

[5131] interface bus_ts_latch_in (type inPortName)

[5132] Name(type outPortName=Value,

[5133] type conditionPortName=Condition,

[5134] type clock-PortName=Clock)

[5135] with {data {Pin List}};

[5136] Here, Value, Condition and Clock are all expressions. Valuerefers to the value to output on the pins, Condition refers to thecondition for driving the pins and Clock refers to the signal to clockthe input from the pins. When the second expression is non-zero, thevalue of the first expression is driven on the pins. When the value ofthe second expression is zero, the pins are tri-stated and theregistered value of the external bus can be read using the identifierName.inPortName in much the same way that bus_in interfaces are read. IfinPortName is not defined, the port name defaults to in. The rising edgeof the value of the third expression clocks the external values throughto the internal values on the chip. For example:

[5137] int 1 get;

[5138] int 1 condition;

[5139] int 4 x;

[5140] interface bus_ts_latch_in(int 4 read)

[5141] BiBus(int write=x+1,

[5142] int 1 enable=condition,

[5143] int 1 clock=get)

[5144] with {data={“P1”, “P2”, “P3”, “P4”}};

[5145] condition=0; // Tri-state external pins

[5146] get=0;

[5147] get=1; // Register external value

[5148] x=BiBus.read; // Read registered value

[5149] condition=1; // Drive x+1 onto external pins

[5150] This example samples the external bus and reads the registeredvalue into variable x and then drives the value of x+1 onto the externalpins. Take care when driving tri-state bases that the FPGA and anotherdevice on the bus cannot drive simultaneously as this may result indamage to one or both of them.

[5151] Bi-directional Data Transfer with Clocked Input

[5152] The bus_ts_clock_in interface sort allows Handel-C programs toperform bidirectional off-chip communications via external pins withinputs clocked continuously with the Handel-C clock. Its general usageis:

[5153] interface bus_ts_clock_in (type inPortName)

[5154] Name(type outPortName=Value,

[5155] type conditionPortName=Condition)

[5156] with {data={Pin List}

[5157] Here, Value and Condition are expressions. Value refers to thevalue to output on the pins and Condition refers to the condition fordriving the pins. When the Condition is non-zero (i.e. true), the valueof Value is driven on the pins. When the value of Condition is zero, thepins are tri-stated and the value of the external bus can be read usingthe identifier Name.InPortName in much the same way that bus_ininterfaces are read.

[5158] _The rising edge of the Handel-C clock reads the external valuesinto the internal flip-flops on the chip. For example:

[5159] int 1 condition;

[5160] int4 x;

[5161] interface bus_ts_clock_in (int 4 read

[5162] BiBus(int 4 writePort=x+1,

[5163] int 1 enable=condition)

[5164] with {data={“P1”, “P2”, “P3”, “P4”}};

[5165] condition=0;// Tri-state external pins

[5166] x=BiBus.read;// Read registered value

[5167] condition=1;// Drive x+1 onto external pins

[5168] This example reads the value from the flip-flop into variable xand then drives the value of x+1 onto the external pins. Take care whendriving tri-state buses that the FPGA and another device on the buscannot drive simultaneously as this may result in damage to one or bothof them.

[5169] Merging Pins

[5170] It is possible to merge pins:

[5171] merge input pins with double declarations of input bus interfaces

[5172] merge tri-state pins

[5173] Input pins can be merged so that pins can be read simultaneouslyinto multiple variables. This can be done by specifying multipleinterfaces (bus_in, bus_clock_in, bus_latch_in) which have some pins incommon. If required, a different subset of pins can be specified foreach instance of the interface. For example:

[5174] interface bus_in(int 8 wide) wideDataBus( ) with

[5175] {data={“P1”, “P2”, “P3”, “P4”, “P5”,

[5176] “P6”, “P7”, “P8”}};

[5177] interface bus₁₃ in(int 3 thin) thinDataBus( ) with

[5178] {data={“P3”, “P4”, “P5”}};

[5179] wideDataBus.in would give the values of pins 1-8, whereasthinDataBus.in would give the three bit value on pins 3,4 and 5.Tri-state bus pins can be merged, though doing so may generate acompiler warning, as the compiler cannot detect whether there is aconflict in the use of the merged pins. One might wish to merge outputpins for a tri-state bus if he or she wished to switch the circuitconnections from one external piece of logic to another. For example:

[5180] int 1 en1, en2;

[5181] int 4 x, y;

[5182] interface bus ts_clock_in (int 4 read

[5183] BiBus1(int 4 writePort=x+1, en1==1)

[5184] with {data={“P1”, “P2”, “P3”, “P4”}};

[5185] interface bus_ts_clock_in (int 4 read

[5186] BiBus2(int 4 writePort=y+1, en2==1)

[5187] with {data={“P1”, “P2”, “P3”, “P4”}};

[5188] Take care when driving tri-state buses that the FPGA and anotherdevice on the bus cannot drive simultaneously as this may result indamage to one or both of them.

[5189] Buses and the Simulator

[5190] The Handel-C simulator cannot simulate buses directly. Therecommended process for debugging is to use the channel method outlinedearlier in this section of the present description. This is because thesimulation of buses cannot determine when input and output should occur.

[5191] By using the #define and #ifdef . . . #endif constructs of thepreprocessor, it is possible to combine both the simulation and hardwareversions of the program into one. For example:

[5192] #define SIMULATE

[5193] #ifdef SIMULATE

[5194] input ? value;

[5195] #else

[5196] value=BusIn.in;

[5197] #endif

[5198] Refer to the Handel-C Preprocessor section for details ofconditional compilation. Simulation of buses may be important whendebugging the interface with the outside world. In this case, one canuse the Application Programmers Interface (API) to write a plugin whichcan be co-simulated. For example, to simulate a tri-state bus:

[5199] #ifdef SIMULATE

[5200] interface bus_ts (uint 32 in with

[5201] {extlib=“cosim_hc.dll”,extinst=“1”,extfunc=“DataBusIn”})

[5202] DataBus (DataOut with {extlib=“cosim_hc.dll”,

[5203] extinst=“1”, extfunc=“DataBusOut”},

[5204] !WriteBus.in with {extlib=“cosim_hc.dll”,

[5205] extinst=“1”, extfunc=“DataBusEnable”}

[5206] );

[5207] #else

[5208] interface bus_ts (uint 32 in with {data=pinList})

[5209] DataBus (DataOut, !WriteBus.in)

[5210] with {data=pinList})

[5211] #endif

[5212] In this case, the functions DataBusIn, DataBusOut andDataBusEnable would be provided in the plugin cosim_hc.dll and called bythe simulator. Details of using the API to write plugins are givenherein.

[5213] Timing Considerations for Buses

[5214] It is sometimes important to be aware of the timing of theexternal interfaces. While Handel-C without hardware libraries does notallow one to control exact timings, some care when writing code canallow enough control to make such interfaces work. The firstconsideration is for bus_in interfaces. This form of bus is built withno register between the external pin and the points inside the FPGAwhere the data is used. Thus, if the value on the external pin changesasynchronously with the Handel-C clock then routing delays within theFPGA can cause the value to be read differently in different parts ofthe circuit. For example:

[5215] interface bus_in(int 1 read) a( ) with

[5216] {data {“P1”}};

[5217] par

[5218] {

[5219] x=a.read;

[5220] y=a.read;

[5221] }

[5222] Even though a.read is assigned to both x and y on the same clockcycle, if the delay from pin 1 to the flip-flop implementing the xvariable is significantly different from that between pin 1 and theflip-flop implementing the y variable then x and y may end up withdifferent values. This can be seen by considering the timing of somesignals.

[5223] Here, the delay between pin 1 and the input of y is slightlylonger than the delay between pin 1 and the input to x. As a result,when the rising edge of the clock registers the values of x and y, thereis one clock cycle when x and y have different values. FIG. 76illustrates a timing diagram 7600, in accordance with one embodiment ofthe present invention.

[5224] This effect can also occur in places that are more obscure. Forexample:

[5225] interface bus_in(int 1 read) a( ) with

[5226] {data={“P1”}};

[5227] while (a.read==1)

[5228] {

[5229] x=x+1;

[5230] }

[5231] In this example, although a.read is only apparently used once,the implementation of a while loop requires the signal to be routed totwo different locations giving the same problem as before. The solutionto this problem is to use either a bus_latch_in or a bus_clock_ininterface sort.

[5232] There is also a timing issue with output buses that needs carewhen designing interface hardware. In this case, the value output onpins cannot be guaranteed except at rising Handel-C clock edges. Inbetween clock edges, the value may be in the process of changing.

[5233] Since the routing delays through different parts of the logic ofthe output expression are different, some pins may change before othersgiving rise to intermediate values appearing on the pins. This isparticularly apparent in deep combinatorial logic. For example:

[5234] int 8 x;

[5235] int 8 y;

[5236] interface bus_out( ) output(write=x * y)

[5237] with {data=“P1”, “P2”, “P3”, “P4”,

[5238] “P5”, “P6”, “P7”, “P8”}};

[5239] Here, a multiplier contains deep logic so some of the 8 pins maychange before others leading to intermediate values. It is possible tominimize this effect (although not eliminate it completely) by adding avariable before the output. This effectively adds a flip-flop to theoutput. The above example then becomes:

[5240] int 8 x;

[5241] int 8 y;

[5242] int 8 z;

[5243] interface bus_out( ) output(write=z)

[5244] with {data={“P1”, “P2”, “P3”, “P4”,

[5245] “P5”, “P6”, “P7”, “P8”}};

[5246] z=x * y;

[5247] Care may now be taken because the value of z may be updatedwhenever the value output on the bus may change. Race conditions withinthe combinatorial logic can lead to glitches on output pins betweenclock edges. When this happens, pins may glitch from 0 to 1 and back tozero or vice versa as signals propagate through the combinatorial logic.Adding a flip-flop at the output in the manner described above removesthese effects. These considerations should also be taken into accountwhen using bi-directional tri-state buses since these are effectively acombination of an input bus and an output bus.

[5248] Metastability

[5249] The output of a digital logic gate is a voltage level thatnormally represents either ‘0’ or ‘1’. If the voltage is below the lowthreshold, it represents 0 and if it is above the high threshold, itrepresents 1. However, if the voltage input to a register or latch isbetween these thresholds on the clock edge, then the output of thatregister may be indeterminate for a time before reverting to one of thenormal states. The state to which it reverts and the time at which itreverts cannot be predicted. This is called metastability, and can occurwhen data is clocked into a register during the time when the data ischanging between the two normal voltage levels representing 0 and 1. Itis therefore an important consideration for Handel-C programs that mayclock in data when the data is changing state. The metastabilitycharacteristics of digital logic devices vary enormously. For adiscussion of Xilinx FPGAs see the Xilinx FPGA data sheet (reference 2).This section puts the problem into perspective. For example a XC4000Edevice clocking a 1 MHz data signal with a 10 MHz clock is expected onlyonce in a million years to take longer than 3 ns to recover from ametastable state to a stable state. So when designing a system examinethe metastability characteristics of the devices under the conditions inwhich they may be used to determine whether any precautions need betaken.

[5250] The ideal system is designed such that when data is clocked intoa register it is guaranteed to be stable. This can be achieved by usingintermediate buffer storage between the two systems that aretransferring data between each other. This storage could be a singledual-port register, dual-port memory, FIFO, or shared memory.Handshaking flags are used to indicate that data is ready, and that datahas been read. However even in this situation sampling of the flagscould cause metastability. The solution is to clock the flag into theHandel-C program more than once, so it is clocked into one register, andthe output of that register is then clocked into another register. Onthe first clock the flag could be changing state so the output could bemetastable for a short time after the clock. However, as long as theclock period is long relative to the possible metastable period, thesecond clock may clock stable data. Even more clocks further reduce thepossibility of metastable states entering the program, however the movefrom one clock to two clocks is the most significant and should beadequate for most systems.

[5251] The example below has 4 clocks. The first is in the bus_clock_inprocedure, and the next 3 are in the assignments to the variables x, y,and z.

[5252] int 4 x,y,z;

[5253] interface bus_clock_in(int 4 read) InBus( ) with

[5254] {data={“P1”, “P2”, “P3”, “P4”}};

[5255] par

[5256] {

[5257] while(1)

[5258] x=InBus.read;

[5259] while(1)

[5260] y=x;

[5261] {

[5262] ......

[5263] z=y

[5264] }

[5265] }

[5266] Remember to keep the problem in perspective by examining thedetails of the system to estimate the probability of metastability.Design the system in the first place to minimize the problem bydecoupling the FPGA from external synchronous hardware by using externalbuffer storage.

[5267] Metastability Across Clock Domains

[5268] There are particular metastability issues when dealing withcommunications across clock domains. Channels that connect between clockdomains are unidirectional point-to-point. The timing between domains isunspecified, but the transmission is guaranteed to occur, and both sidesmay wait until the transmission has completed. For example:

[5269] //File: transmit.c

[5270] chan 8 c;// channel may have global scope

[5271] void main(void)

[5272] {

[5273] int 8 x, y,

[5274] c ! x;//program may wait until data

[5275] //successfully transmitted

[5276] c ! y;

[5277] }

[5278] //File: receive.c

[5279] extern chan c;

[5280] void main(void)

[5281] {

[5282] int 8 p, q;

[5283] c ? p;

[5284] c ? q;

[5285] {

[5286] Ports

[5287] If one is dealing with hardware components in separate clockdomains, one may need to insert resynchronising hardware if it is notincluded in the components. For example, if data is sent from port_out Ain domain bbA and received from port_in B in domain bbB, the data may beresynchronized to the clock in domain bbB. This can be done by using thedata at least once in the Handel-C wrapper file.

[5288] The example below shows the three files required to connect twoEDIF blocks (bbA and bbA) which use different clocks. The small filesbbA.c and bbB.c connect to the EDIF code using the port_out from andport_in to interfaces. The metastable.c file generates one flip-flopthat resynchronizes the data by reading the value from bbA into avariable.

[5289] File: metastable.c

[5290] /*

[5291] * Black box code to resynchronize

[5292] * Needs to be clocked from the reading clock

[5293] * (i.e. bbB-c's clock)

[5294] */

[5295] int 1 x;

[5296] interface bbA(int 1 from) A( );

[5297] interface bbB( ) B(int 1 to=x);

[5298] main( )

[5299] {

[5300] while(1)

[5301] {

[5302] /* stabilize the data by adding

[5303] * resynchronization FF

[5304] */

[5305] x=A.from;

[5306] {

[5307] {

[5308] File: bbA.c

[5309] /*

[5310] * Domain bbA

[5311] * Connects to bbA.edf

[5312] */

[5313] void main(void)

[5314] {

[5315] int 1 y;

[5316] interface port_out( ) from (int 1 from y);

[5317] {

[5318] File: bbB.c

[5319] /*

[5320] *Domain bbB

[5321] * Connects to bbB.edf

[5322] */

[5323] void main(void)

[5324] {

[5325] int 1 q:

[5326] interface port in(int 1 to) too;

[5327] par

[5328] {

[5329] while(1)

[5330] {

[5331] q=to.to: // Read data

[5332] }

[5333] }

[5334] }

[5335] Alternatively, the resynchronising flip-flop can be placed in thefile that reads the data from the foreign code block.

[5336] File: toplevel.c

[5337] /*

[5338] * Code to connect data between two cores

[5339] */

[5340] interface bbA(int 1 from) A( );

[5341] interface bbB( ) B(int 1 to=A.from);

[5342] File: bbA.c

[5343] /*

[5344] * Domain bbA

[5345] * Compiles to bbA.edf

[5346] */

[5347] void main(void)

[5348] {

[5349] int 1 y;

[5350] interface port_out( ) from (int 1 from=y);

[5351] }.Handel=C Language

[5352] File: bbB.c

[5353] /*

[5354] *Domain bbB

[5355] * Complies to bbB.edf

[5356] */

[5357] void main(void)

[5358] {

[5359] int 1 q, y;

[5360] interface port in(int 1 to) to( );

[5361] while(1)

[5362] {

[5363] par

[5364] {

[5365] q=to.to; // Resynchronize data

[5366] y=q;

[5367] }

[5368] }

[5369] }

[5370] Interfacing with External Logic

[5371] Handel-C provides the interface sorts port_in and port_out. Theseallow one to have a set of wires, unconnected to pins, which he or shecan use to connect to a simulated device or to another function withinthe FPGA. It is assumed that Handel-C has supplied an interfacedeclaration for these sorts, and one supply an instance definition.

[5372] port_in

[5373] For a port_in, one defines the port(s) carrying data to theHandel-C code and any associated specifications.

[5374] interface port_in(Type data_TO_hc [with {port_specs}])

[5375] Name( ) [with {Instance_specs}];

[5376] For example:

[5377] interface port_in(int 4 signals_to_HC) read( );

[5378] One can then read the input data from the variableName.data_TO_hc, in this case read.signals_to_HC

[5379] port_out

[5380] For a port_out, one define the port(s) carrying data from theHandel-C code, the expression to be output over those ports, and anyassociated specifications.

[5381] interface port_out( ) Name(Type data_FROM_hc=

[5382] output_Expr[with {port_specs}])

[5383] [with {Instance_specs}];

[5384] For example:

[5385] int X_out;

[5386] interface port_out( )

[5387] drive(int 4 signals_from_HC=X_out);

[5388] In this case, the width of X_out would be inferred to be 4, asthat is the width of the port that the data is sent to.

[5389] Specifying the Interface

[5390]FIG. 76A is a flowchart 7650 showing a method for providing aversatile interface. First, in operation 7652, computer code is writtenin a first programming language. Included in the first computer code isreference to second computer code in a second programming language. Seeoperation 7654. In one aspect of the present invention, the reference tothe second computer code may include a predetermined command in thefirst computer code. In yet a further aspect, the second programminglanguage may be either EDIF or VDHL.

[5391] The second computer code is simulated in the second programminglanguage for use during the execution of the first computer code in thefirst programming language. Note operation 7656. In an aspect of thepresent invention, the second computer code may be simulated by a firstsimulator module. In such an aspect, the first simulator module mayinterface a second simulator module. As a further option, the firstsimulator module may interface the second simulator module via a plug-inmodule.

[5392]FIG. 77 illustrates the manner in which an interface 7700 isspecified, in accordance with one embodiment of the present invention.One can specify any particular interface format. This allows he or sheto communicate with code written in another language 7702 such as VHDLor EDIF and allows the Handel-C simulator 7704 to communicate with anexternal plugin program 7706 (e.g., a connection to a VHDL simulator).The expected use for this is to allow one to incorporate bought-in orhandcrafted pieces of low-level code in the high-level Handel-C program.It also allows the Handel-C program code be incorporated within a largeEDIF or VHDL program. One can also use it to communicate with programsrunning on a PC that simulate external devices.

[5393] To use such a piece of code requires that one include aninterface declaration in the Handel-C code to connect it to the externalcode block. This declaration also tells the simulator to call a plugin(which in turn may invoke a simulator for the foreign code).

[5394] Handel-C code Required

[5395] The code needed in the Handel-C program is in two parts. First, aperson needs an interface declaration In the simplest form, this is ofthe format:

[5396] interface sort ({extern_to_HC_ort{, extern_to_HC_port}})({HC_to_extern_port{, HC_to_extern_port}})

[5397] where:

[5398] sort is the name one gives to this type of interface

[5399] extern_to_HC_port is the prototype (type and name) of an inputport used to communicate from the external code to the Handel-C.

[5400] HC_to_extern_port is the prototype (type and name) of an outputport used to communicate with the external code from the Handel-C. Atleast one port (input or output) may be declared. One then needs todefine an instance of the interface in the format:

[5401] interface sort({extern_to_HC_port})

[5402] Name({HC_to_extern_port=data_from_HC_to_extern

[5403] [with {portSpec}]{,HC_to_extern_port=

[5404] data_from_HC_to_extern

[5405] [with {portSpec}]}})

[5406] [with {extlib=“simulator_plugin”, specs}]

[5407] where:

[5408] sort is the name one gives to this sort of interface

[5409] extern_to_HC_port is the definition of the previously declaredport. This definition may include an optional with specification.

[5410] with {portSpec} is optional. It consists of one or more portspecifications for a single port in the interface

[5411] name is the name one gives to this definition of the interface

[5412] HC_to_extern_port is the definition of the previously declaredport. This definition may include a with specification.

[5413] data_from_HC_to_extern is an expression which may be sent to theexternal code from the Handel-C.

[5414] simulator_plugin is the name of a file on the PC which managesthe cosimulation. It provides the inputs to and the data from theexternal code. (This plugin file may in turn invoke another simulator.).Its presence is optional.

[5415] specs are instance specifications required (some of these maydepend on the cosimulator file plugin).

[5416] Targeting Specific Tools

[5417] When compiling to EDIF, Handel-C has the capacity to format thenames of wires to external logic according to the different syntaxesused by place and route tools. One can do this using the busformatspecification to a port. This allows one to specify how the bus name andwire number are formatted.

[5418] To specify a format, one uses the syntax:

[5419] port with {busformat=“formatString”}.

[5420] formatstring can be one of the following strings. B representsthe bus name, and 1 represents the wire number.

[5421] B1

[5422] B_(—)1

[5423] B[1]

[5424] B(1)

[5425] B<1>

[5426] Example

[5427] interface port_in(int 4 signals_to_HC with

[5428] {busformat=“B[1]) read( );

[5429] would produce wires

[5430] signals_to_HC[0]

[5431] signals_to_HC[1]

[5432] signals_to_HC[2]

[5433] signals_to_HC[3]

[5434] ram unsigned 4 rax[4] with {ports 1, busformatΔ“B<1>”};

[5435] would produce wires

[5436] rax_SPPort_addr<0> //Address

[5437] rax_SPPort_addr<1>

[5438] rax_SPPort_data_in<0> //Data In

[5439] rax_SPPort_data_in<1>

[5440] rax_SPPort_data_in<2>

[5441] rax_SPPort_data_in<3>

[5442] rax_SPPort_data_out<0> //Data Out

[5443] rax_SPPort_data_out<1>

[5444] rax_SPPort_data_out<2>

[5445] rax_SPPort_data_out<3>

[5446] rax_SPPort_data_en//Data Enable

[5447] rax_SPPort_elk//Clock

[5448] rax_SPPort_cs//Chip Select

[5449] rax_SPPort_oe//Output Enable

[5450] rax_SPPort_we//Data In.

[5451] Object Specifications

[5452] Handel-C provides the ability to add ‘tags’ to certain objects(variables,channels, ports, buses, RAMs, ROMs, mprams and signals) tocontrol their behavior. These tags or specifications are listed afterthe declaration of the object using the with keyword. This keyword takesone or more of the following attributes.

[5453]FIGS. 78A through 78C illustrates a table showing thespecification of various keywords 7800, in accordance with oneembodiment of the present invention. The previous sections have alreadyshown briefly how to use some of these specifications but this sectioncovers these in more detail and also describes the other specificationsin the table above.

[5454] Specifications can be added to objects as follows:

[5455] unsigned 4 w with {show=0};

[5456] int 5 x with {show=0, base=2};

[5457] chanout char y with {outfile=“output.dat”};

[5458] chanin int 8 z with {infile=“input.dat”};

[5459] interface bus_clock_in(int 4 in) InBus( ) with

[5460] {pull=1,

[5461] data=“P1”, “P2”, “P3”, “P4”}

[5462] };

[5463] When declaring multiple objects, the specification may be givenat the end of the line and applies to all objects declared on that line.For example:

[5464] unsigned x, y with {show=0};

[5465] This attaches the show specification with a value of 0 to both xand y variables.

[5466] Details of each of the specifications are given below.

[5467] The Show Specification

[5468] The show specification may be given to variable, channel, outputbus and tri-state bus declarations. When set to 0, this specificationtells the Handel-C simulator not to list this object in its output. Thismeans that it may not appear in the Variables debug window in the GUI.

[5469] The default value of this specification is 1.

[5470] Reducing the number of items displayed in the output list fromthe simulator produces a noticeable speed up in simulation.

[5471] The Base Specification

[5472] The base specification may be given to variable, output channel,output bus and tri-state bus declarations. The value that thisspecification is set to tells the Handel-C compiler which base todisplay the value of the object in. Valid bases are 2, 8, 10 and 16 forbinary, octal, decimal and hexadecimal respectively. The default valueof this specification is 10.

[5473] The Infile and Outfile Specifications

[5474] The infile specification may be given to chanin, bus_in,bus_latch_in, bus_clock_in, bus_ts, bus_ts_latch_in and bus_ts_clock_indeclarations. The outfile specification may be given to chanout,bus_out, bus_ts, bus_ts_latch_in and bus_ts_clock_in declarations. Thestrings that these specifications are set to may inform the simulator ofthe file that data should be read from (infile) or the file that datashould be written to (outfile). When applied to a variable, the state ofthat variable at each clock cycle is placed in that file when simulationtakes place. Note that when applying the outfile specification, itshould not be given to multiple variables or channels. For example, thefollowing declarations are not allowed:

[5475] int x, y with {outfile=“out.dat”};

[5476] chanout a, b with {outfile=“out.dat”};

[5477] For details of connecting channels to files. By default, no inputor output files are used.

[5478] The Warn Specification

[5479] The warn specification may be given to a variable, RAM, ROM,channel or bus. When set to zero, certain non-crucial warnings may bedisabled for that object. When set to one (the default value), allwarnings for that object may be enabled.

[5480] warn=0 The speed specification

[5481] The speed specification may be given to an output or tri-statebus. The value of this specification controls the slew rate of theoutput buffer for the pins on the bus. For Xilinx devices, 0 is slow, 3is fast, and the default value is 3. For Altera devices, 0 is slow, 1 isfast, and the default value is 1.

[5482] Refer to the Xilinx or Altera FPGA data sheets for details ofslew rate control

[5483] The Intime and Outtime specifications

[5484] The intime specification may be given to an input port or bus,tri-state bus or off-chip memory. The outtime specification may be givento an output port or bus, tri-state bus or off-chip memory. When appliedto Xilinx chips, these specifications cause Handel-C to generate aNetlist Constraints File (NCF) for the design. The place-and-route toolsthen use this file to constrain the relevant paths.

[5485] intime specifies the maximum delay in ns allowed between aninterface or memory and the elements it feeds.

[5486] outtime specifies the maximum delay in ns allowed between aninterface or memory and the elements it is fed from. They can befloating point numbers. For example:

[5487] macro expr memoryPins={“P6”, “P7”, “P8”,

[5488] “P9”, “P10”, “P11”, “P12”, “P13”, };

[5489] macro expr dataPins={“P1”, “P2”, “P3”, “P4”};

[5490] interface bus_in(unsigned 4) hword( ) with {data=dataPins,

[5491] intime=5};

[5492] interface port_out( )

[5493] (unsigned 4 out=hword.in+1)

[5494] with {outtime=5.2};

[5495] ram int 8 a[15][43] with {outtime=5.2,

[5496] offchip=1,

[5497] data=memorypins};

[5498] The Busformat Specification

[5499] The busformat specification may be given to an interface, port ormemory that is resident in external logic. When compiled to EDIF, thebusformat string defines the format of the wire names. Valid values forthe busformat string are:

[5500] B1B_(—)1 B[1] B(1)

[5501] B represents the bus name and 1 the wire number.

[5502] The default format is B_(—)1

[5503] The Pull Specification

[5504] The pull specification may be given to an input or tri-state bus.When set to 1, a pull up resistor is added to each of the pins of thebus. When set to 0, a pull down resistor is added to each of the pins ofthe bus. When this specification is not given for a bus, no pull up orpull down resistor is used. Altera devices do not have pull-up orpull-down resistors. Refer to the Xilinx FPGA data sheet for details ofpull up and pull down resistors. By default, no pull up or pull downresistors are attached to the pins.

[5505] The Data Specification

[5506] The data specification may be given to an external interface ormemory. It consists of a list of pin numbers separated by commas. If thedata specification is omitted, the place and route tools may assign thepins.

[5507] macro expr memoryPins={“P6”, “P7”, “P8”,

[5508] “P9”, “P10”, “P11”, “P12”, “P 13”};

[5509] macro expr dataPins={“P1”, “P2”, “P3”, “P4”};

[5510] interface bus_in(unsigned 4) hword( ) with {data dataPins,

[5511] intime=5};

[5512] ram int 8 a[15][43] with {data=memoryPins};

[5513] The Offchip Specification

[5514] The offchip specification may be given to a RAM or ROMdeclaration. When set to 1, the Handel-C compiler builds an externalmemory interface for the RAM or ROM using the pins listed in the addr,data, cs, we and oe specifications (see below). When set to 0, theHandel-C compiler builds the RAM or ROM on the FPGA and ignores any pinsgiven with other specifications.

[5515] intime and outtime specifications can also be applied to off-chipRAMs. If they have not been given, the compiler attempts to build themfrom the rate, westart, and welength specifications. If any of these aremissing, the compiler does not calculate time specs for the memory.

[5516] ram int 8 a[15][43] with {offchip=1};

[5517] The Ports Specification

[5518] The ports specification may be given to a RAM or ROM declaration.When set to 1, the Handel-C compiler builds an external memory interfacefor the RAM or ROM using the ports defined in the addr, data, Cs, we andoe specifications (see below). This allows one to connect to RAMs inexternal code. The compiler generates an error if the ports and offchipspecification are both set to 1 for the same memory. All otherspecifications can be applied. If the ports specification is applied toan MPRAM, a separate interface may be generated for each port.

[5519] The Xilinx Block Specification

[5520] The block specification may be given to a RAM or ROM declaration.One can specify that a block RAM is created in a Xilinx Virtex chip byusing the specification block=1. E.g.

[5521] ram int 8 a[15][43] with {block=1};

[5522] The default block specification is 0 (not in block memory).

[5523] The Wegate Specification

[5524] The wegate specification may be given to external or internal RAMdeclarations to force the generation of an asynchronous RAM. When set to0, the write strobe may appear throughout the Handel-C clock cycle. Whenset to −1, the write strobe may appear only in the first half of theHandel-C clock cycle. When set to 1, the write strobe may appear only inthe second half of the Handel-C clock cycle.

[5525] The Westart and Welength Specifications

[5526] The westart and welength specifications may be given to internalor external RAM declarations. One can only use these specificationstogether with external_divide or internal_divide clock types with adivision factor greater than 1.

[5527] The westart and welength specifications position the write enablestrobe within the Handel-C clock cycle.

[5528] The rclkpos, wclkpos, clkpulselen and clk Specifications

[5529] The rclkpos, wclkpos and clkpulselen may be given to internal orexternal SSRAM declarations. The elk specification is used for externalSSRAM declarations. To use these specifications, one may be using theexternal_divide or internal_divide clock types with a division factor of2 or more.

[5530] rclkpos specifies the positions of the clock cycles of the newram clock RAMCLK, for a read cycle. These positions would be specifiedin terms of cycles of a fast external clock CLK, counting forwards fromthe rising edge of the Handel-C clock HCLK rising edge.

[5531] wclkpos specifies the positions of the clock cycles of the newram clock RAMCLK, for a write cycle.

[5532] clkpulselen specifies the length of the pulses of the new RAMclock RAMCLK, in terms of cycles of CLK. This is specified only once fora RAM. It thus applies to both the read and write clocks.

[5533] clk specifies the pin(s) that carry the new RAM clock RAMCLK tothe external SSRAM.

[5534] Specifying Pin Outs

[5535] The addr, data, we, cs and oe specifications each take a list ofdevice pins and are used to define the connections between the FPGA andexternal devices. FIG. 78D illustrates the manner in which an pin outsare specified 7850, in accordance with one embodiment of the presentinvention.

[5536] Pin lists are always given in the order most significant to leastsignificant. Multiple write enable, chip select and output enable pinscan be given to allow external RAMs and ROMs to be constructed frommultiple devices. For example, when using two 4-bit wide chips to makean 8-bit wide RAM, the following declaration could be used:

[5537] ram unsigned 8 ExtRAM[256] with {offchip=1,

[5538] addr={“P1”, “P2”, “P3”, “P4”,

[5539] “P5”, “P6”, “P7”, “P8”},

[5540] data={“P9”, “P10”, “P11”, “P12”,

[5541] we={“P17”, “P18”},

[5542] cs={“P19”, “P20”},

[5543] oe={“P21”, “P22”}};

[5544] The Rate Specifications

[5545] The rate specification may be given to a clock to specify themaximum delay in ns allowed between components fed from that clock. Thisspecification causes Handel-C to generate a Netlist Constraints File(NCF) for the design. The place-and-route tools then use this file toconstrain the relevant paths so that the part of the design connected tothe clock in question can be clocked at the specified rate. rate may bea floating-point number. For example:

[5546] set clock=external_divide “D17”4 with

[5547] {rate=1.4};.

[5548] Example Hardware Interface

[5549] An example, theoretical interface is now described to illustratethe use of buses. The scenario is of an external device connected to theFPGA which may be read from or written to. The device has a number ofsignals connected to the FPGA. FIG. 79 illustrates the various signals7900 employed by the present invention.

[5550] A read from the device is performed by waiting for ReadRdy tobecome active (high). The Read signal is then taken high for one clockcycle and the data sampled on the falling edge of the strobe. FIG. 80illustrates a read waveform representative of a cycle 8000, inaccordance with one embodiment of the present invention.

[5551] A write to the device is performed by waiting for WriteRdy tobecome active (high). The Write signal is then taken high for one clockcycle while the data is driven to the device by the FPGA. The devicesamples the data on the falling edge of the Write signal. FIG. 81illustrates a waveform representative of a write cycle 8100, inaccordance with one embodiment of the present invention.

[5552] The first stage of the code may declare the buses associated witheach of the external signals. The following code does this:

[5553] int 4 Data;

[5554] int 1 En=0;

[5555] interface bus_ts_clock_in(int 4)

[5556] dataB(Data, En==1) with

[5557] {data={“P1”, “P2”, “P3”, “P4”}};

[5558] int 1 Write=0;

[5559] interface bus_out( ) writeB(Write) with

[5560] {data={“P5”}};

[5561] int 1 Read=0;

[5562] interface bus_out( ) readB(Read) with

[5563] {data={“P6”}};

[5564] interface bus_clock_in(int 1)

[5565] WriteReady( ) with {data={“P7”}};

[5566] interface bus_clock_in(int 1) ReadReady( ) with

[5567] {data={“P8”}};

[5568] The values on the output buses will now be changed by setting thevalues of the Data, Write and Read variables. In addition, one can drivethe data bus with the contents of Data by setting En to 1. Note that thevariables that drive buses have been initialized to 0 so these variablesmay be static or global. This may be important when driving writestrobes as in the present case. Care should be taken duringconfiguration that the FPGA pins are disconnected in some way from theexternal devices because the FPGA pins become tri-state during thistime.

[5569] The main program reads a word from the external device beforewriting one word back.

[5570] void main (void)

[5571] {

[5572] int 4 Data;

[5573] // Read word from external device

[5574] while (ReadReady 0)

[5575] delay;

[5576] Read 1; // Set the read strobe

[5577] par

[5578] {

[5579] Data=dataB.in; // Read the bus

[5580] Read 0; // Clear the read strobe

[5581] }

[5582] // Write one word back to external device

[5583] Reg=Data+1;

[5584] while (WriteReady==0)

[5585] delay;

[5586] par

[5587] {

[5588] En=1; // Drive the bus

[5589] Write=1; // Set the write strobe

[5590] }

[5591] Write=0; // Clear the write strobe

[5592] En=0; // Stop driving the bus

[5593] Note that during the write phase, the data bus is driven for oneclock cycle after the write strobe goes low to ensure that the data isstable across the falling edge of the strobe.

[5594] Standard Macro Expressions

[5595] Introduction

[5596] The Handel-C compiler is provided with a standard header filecontaining a collection of useful macro expressions. This header filemay be used by simply including it in the Handel-C program with thefollowing line:

[5597] #include <stdlib.h>

[5598] Note that this header file is not the same as the conventional Cstdlib.h header file but contains a standard collection of definitionsuseful to the Handel-C programmer.

[5599] The definitions themselves are included in the stdlib.liblibrary, which is supplied in the Handel-C\Lib directory. One may ensurethat he or she has included this directory in the library include pathif he or she uses the macro definitions. The following sections describeeach macro in detail.

[5600] Constant Definitions

[5601] The stdlib.h header file contains the following constantdefinitions:

[5602] Constant Name Definition

[5603] TRUE 1

[5604] FALSE 0

[5605] These definitions often lead to cleaner and more readable codeFor example:

[5606] int 8 x with {show=FALSE};

[5607] while (TRUE)

[5608] {

[5609] ......

[5610] }

[5611] if(a==TRUE)

[5612] {

[5613] ......

[5614] Bit Manipulation Macros

[5615] The stdlib.h header file contains a number of macro expressionsused to manipulate bits and bit fields listed below.

[5616] Adjs

[5617] Usage: adjs( Expression, Width)

[5618] Parameters:

[5619] Expression Expression to adjust (may be signed integer)

[5620] Width Width to adjust to

[5621] Returns:

[5622] Signed integer of width Width.

[5623] Description:

[5624] Adjusts width of signed expression up or down. Sign extends MSBsof expression when expanding width. Drops MSBs of expression whenreducing width.

[5625] Example:

[5626] int 4 x;

[5627] int 5 y;

[5628] int 6 z;

[5629] y=15;

[5630] x=adjs(y, width(x)); //x=7

[5631] y=-4;

[5632] z=adjs(y, width(z)); //z=-4.

[5633] Adju

[5634] Usage: adju( Expression, Width )

[5635] Parameters:

[5636] Expression Expression to adjust (may be unsigned integer)

[5637] Width Width to adjust to

[5638] Returns:

[5639] Unsigned integer of width Width.

[5640] Description:

[5641] Adjusts width of unsigned expression up or down. Zero pads MSBsof expression when expanding width. Drops MSBs of expression whenreducing width.

[5642] Example:

[5643] unsigned 4 x;

[5644] unsigned 5 y;

[5645] unsigned 6 z;

[5646] y=14;

[5647] x=adju(y, width(x)); //x=14

[5648] z=adju(y, width(z)); // z=14.

[5649] Copy

[5650] Usage: copy( Expression, Count )

[5651] Parameters:

[5652] Expression Expression to copy

[5653] Count Number of times to copy

[5654] Returns:

[5655] Expression duplicated Count times.

[5656] Returned expression is of same type as Expression

[5657] Returned width is Count * width (Expression).

[5658] Description:

[5659] Duplicates a bit field multiple times.

[5660] Example:

[5661] unsigned 32 x;

[5662] unsigned 4 y;

[5663] y=0xA;

[5664] x=copy(y, 8); //x=0xAAAAAAAA.

[5665] Lmo

[5666] Usage: lmo( Expression )

[5667] Parameters:

[5668] Expression Expression to calculate left most one of.

[5669] Returns:

[5670] Bit position of left most one in Expression or width(Expression)if Expression is zero. Return value is log2(width(Expression))+1 bitswide.

[5671] Description:

[5672] Finds the position of the most significant 1 bit in anexpression.

[5673] Example:

[5674] int 4 x;

[5675] int 3 y;

[5676] x=3;

[5677] y=lmo(x); // y=1

[5678] x=0;

[5679] y=lmo(x); // y=4;

[5680] lmz

[5681] Usage: lmz( Expression )

[5682] Parameters:

[5683] Expression Expression to calculate left most zero of.

[5684] Returns:

[5685] Bit position of left most zero in Expression or width(Expression)if Expression is all ones. Return value is log2(width(Expression))+1bits wide.

[5686] Description:

[5687] Finds the position of the most significant 0 bit in anexpression.

[5688] Example:

[5689] int 4 x;

[5690] int 3 y;

[5691] x=3;

[5692] y=lmz(x); // y=2

[5693] x=15;

[5694] y=lmz(x); // y4;.

[5695] Population

[5696] Usage: population( Expression )

[5697] Parameters:

[5698] Expression Expression to calculate population of.

[5699] Returns:

[5700] Value of same type as Expression,

[5701] Description:

[5702] Counts the number of 1 bits (population) in Expression.

[5703] Example:

[5704] int 4x;

[5705] int 3 y;

[5706] x=0b1011;

[5707] y=population(x); // 3.

[5708] Rmo

[5709] Usage: rmo( Expression )

[5710] Parameters:

[5711] Expression Expression to calculate night most one of.

[5712] Returns:

[5713] Bit position of right most one in Expression or width(Expression)if Expression is zero. Return value is log2(width(Expression))+1 bitswide.

[5714] Description:

[5715] Finds the position of the least significant 1 bit in anexpression.

[5716] Example:

[5717] int 4 x;

[5718] int 3 y;

[5719] x=3;

[5720] y=rmo(x); //y=0

[5721] x=0;

[5722] y=rmo(x); // y=4;.

[5723] Rmz

[5724] Usage: rmz(Expression)

[5725] Parameters:

[5726] Expression Expression to calculate right-most zero of.

[5727] Returns:

[5728] Bit position of right most zero in Expression orwidth(Expression) if Expression is all ones. Return value islog2(width(Expression))+1 bits wide.

[5729] Description:

[5730] Finds the position of the least significant 0 bit in anexpression.

[5731] Example:

[5732] int 4 x:

[5733] int 3 y;

[5734] x=3;

[5735] y=rmz(x); // y=2

[5736] x=15;

[5737] y=rmz(x); // y=4;.

[5738] Top

[5739] Usage: top(Expression, Width)

[5740] Parameters:

[5741] Expression Expression to extract bits from. Width Number of bitsto extract.

[5742] Returns:

[5743] Value of same type as Expression.

[5744] Description:

[5745] Extracts the most significant Width bits from an expression.

[5746] Example:

[5747] int32 x;

[5748] int 8 y;

[5749] x=0x2345678;

[5750] y=top(x, width(y)); // y=0x12.

[5751] Arithmetic Macros

[5752] The stdlib.h header file contains a number of macro expressionsfor mathematical calculations listed below.

[5753] Abs

[5754] Usage: abs(Expression)

[5755] Parameters:

[5756] Expression Signed expression to get absolute value of.

[5757] Returns:

[5758] Signed value of same width as Expression.

[5759] Description:

[5760] Obtains the absolute value of an expression.

[5761] Example:

[5762] int 8 x;

[5763] int 8 y;

[5764] x=34;

[5765] y=-18;

[5766] x=abs(x); // x=34

[5767] y=abs(y); // y=18.

[5768] Addsat

[5769] Usage: addsat(Expression1, Expression2)

[5770] Parameters:

[5771] Expression1 Unsigned operand 1.

[5772] Expression2 Unsigned operand 2. May be of same width asExpression 1.

[5773] Returns:

[5774] Unsigned value of same width as Expression and Expression2.

[5775] Description:

[5776] Returns sum of Expression and Expression 2. Addition is saturatedand result may not be greater than maximum value representable in thewidth of the result.

[5777] Example:

[5778] unsigned 8 x;

[5779] unsigned 8 y;

[5780] unsigned 8 z;

[5781] x=34;

[5782] y=18;

[5783] z=addsat(x, y); // z=52

[5784] x=34;

[5785] y=240;

[5786] z=addsat(x, y); z=255.

[5787] Decode

[5788] Usage: decode(Expression)

[5789] Parameters:

[5790] Expression Unsigned operand.

[5791] Returns:

[5792] Unsigned value of width 2 width(Expression

[5793] Description:

[5794] Returns 2 Expression.

[5795] Example:

[5796] unsigned 4 x;

[5797] unsigned 16 y;

[5798] x=8;

[5799] y=decode(x); // y=0b100000000.

[5800] div

[5801] Usage: div(Expression1, Expression2)

[5802] Parameters:

[5803] Expression1 Unsigned operand 1.

[5804] Expression2 Unsigned operand 2. May be of the same width asExpression1.

[5805] Returns:

[5806] Unsigned value of same width as Expression1 and Expression 2.

[5807] Description:

[5808] Returns integer value of Expression1/Expression2.

[5809] Example:

[5810] unsigned 8 x;

[5811] unsigned 8 y;

[5812] unsigned 8 z;

[5813] x=56;

[5814] y=6;

[5815] z=div(x, y); // z=9

[5816] Warning! Division requires a large amount of hardware and shouldbe avoided unless absolutely necessary.

[5817] exp2

[5818] Usage: exp2(Constant)

[5819] Parameters:

[5820] Constant Operand.

[5821] Returns:

[5822] Constant of width width(Constant)+1.

[5823] Description:

[5824] Used to calculate 2 Constant. Similar to decode but may be usedwith constants of undefined width.

[5825] Example

[5826] unsigned 4 x;

[5827] unsigned (exp2(width(x))) y; // y of width 16

[5828] incwrap

[5829] Usage: incwrap(Expression1, Expression2)

[5830] Parameters:

[5831] Expression1 Operand 1.

[5832] Expression2 Operand 2. May be of same width as Expression1.

[5833] Returns:

[5834] Value of same type and width as Expression1 and Expression2.

[5835] Description:

[5836] Used to increment a value with wrap around at a second value.Returns Expression1+1 or 0 if Expression1+1 is equal to Expression2.

[5837] Example:

[5838] unsigned 8 x;

[5839] x=74;

[5840] x=incwrap(x, 76); // x=75

[5841] x=incwrap(x, 76); // x=0

[5842] x=incwrap(x, 76); // x=1

[5843] log2ceil

[5844] Usage: log2ceil(Constant)

[5845] Parameters:

[5846] Constant Operand.

[5847] Returns:

[5848] Constant value of ceiling(log2(Constant)).

[5849] Description:

[5850] Used to calculate log2 of a number and rounds the result up.Useful to determine the width of a variable needed to contain aparticular value.

[5851] Example:

[5852] unsigned (log2ceil(5768)) x; // x 13 bits wide

[5853] unsigned 8 y;

[5854] y=log2ceil(8); // y=3

[5855] y=log2ceil(7); // y=3

[5856] log2floor

[5857] Usage: log2floor(Constant)

[5858] Parameters:

[5859] Constant Operand.

[5860] Returns:

[5861] Constant value of floor(log2(Constant)).

[5862] Description:

[5863] Used to calculate log2 of a number and rounds the result down.

[5864] Example

[5865] unsigned 8 y;

[5866] y=log2floor(8); // y=3

[5867] y=log2floor(7); // y=2.

[5868] Mod

[5869] Usage: mod(Expression1, Expression2)

[5870] Parameters:

[5871] Expression1 Unsigned operand 1.

[5872] Expression2 Unsigned operand 2. May be of the same width asExpression1.

[5873] Returns:

[5874] Unsigned value of same width as Expression1 and Expression2.

[5875] Description:

[5876] Returns remainder of Expression1 divided by Expression2

[5877] Example:

[5878] unsigned 8 x;

[5879] unsigned 8 y;

[5880] unsigned 8 z;

[5881] x=56;

[5882] y=6;

[5883] z=mod(x, y); // z=2

[5884] Warning! Modulus arithmetic requires a large amount of hardwareand should be avoided unless absolutely necessary.

[5885] Sign

[5886] Usage: sign(Expression)

[5887] Parameters:

[5888] Expression Signed operand.

[5889] Returns:

[5890] Unsigned integer 1-bit wide.

[5891] Description:

[5892] Used to obtain the sign of an expression. Returns zero ifExpression is positive or one if Expression is negative.

[5893] Example:

[5894] int 8 y;

[5895] unsigned 1 z;

[5896] y=53;

[5897] z=sign(y); // z=0

[5898] y=53;

[5899] z=sign(y); // z=1

[5900] subsat

[5901] Usage: subsat(Expression1, Expression2)

[5902] Parameters:

[5903] Expression1 Unsigned operand 1.

[5904] Expression2 Unsigned operand 2. May be of same width asExpression1 .

[5905] Returns:

[5906] Unsigned value of same width as Expression1 and Expression2.

[5907] Description:

[5908] Returns difference between Expression1 and Expression2.Subtraction is saturated and result may not be less than 0.

[5909] Example:

[5910] unsigned 8 x;

[5911] unsigned 8 y;

[5912] unsigned 8 z;

[5913] x=34;

[5914] y=18;

[5915] z=subsat(x, y); // z=16

[5916] x=34;

[5917] y=240;

[5918] z=subsat(x, y); // z=0.13 Clocks

[5919] Multiple Clocks

[5920] One can have multiple clocks interfacing with the design. Eachmain ( ) function may be associated with a clock.

[5921] Internal Clocks

[5922] One can set the clock to be any expression or any expressiondivided by a given factor. For Xilinx 4000 series chips, he or she canset the clock to be a value read from the on-chip clock generator.

[5923] set clock=internal<Expression>;

[5924] set clock=internal_divide<Expression>factor;

[5925] This allows one to set the clock to a value read from aninterface.

[5926] Example

[5927] interface port_in(unsigned 1 elk) ClockPort ( );

[5928] set clock=internal ClockPort.clk;

[5929] External Clocks

[5930] External clocks may be accessed by associating the clock with aspecific pin using set clock external=“pin Name” or set clockexternal_divide=“pin_Name” factor.

[5931] The pin_Name string is optional. If it is omitted, the pins areunconstrained and the place and route tools can assign the pin. One canalso define an interface that reads an external clock. If the clock isassociated with a specific pin, one can use the interface sort bus_in.One would only need to do this if the external clock has been divided,otherwise he or she can use the intrinsic _(—f—)clock (see below).

[5932] Example

[5933] interface bus_in(unsigned 1 in) InputBus ( )

[5934] with {data={“Pin1”}};

[5935] set clock=internal_divide InputBus.in 3;

[5936] One can now use InputBus.in to get an undivided external clock.It may be more efficient to omit the pin specification and allow theplace and route tools to assign the pin.

[5937] interface bus_in(unsigned 1 in) InputBus ( );

[5938] set clock=internal_divide InputBus.in 3;.

[5939] Current Clock

[5940] The current clock used by a function can be referenced using thekeyword_(——)clock. This allows the function to pass the current clock toan external interface. The value of the system variable_clock may be thevalue after any divide. The clock may be an internal or an externalclock.

[5941] Example

[5942] The code below shows the current clock in an interface.

[5943] interface reg32x1k ( ) registers(address, data_in, _clock, write)

[5944] with {extlib=“PluginModelSim.dll”,

[5945] extinst=“1; model=reg32x1k_wrapper; clock=ck:25”};

[5946] Communicating Between Clock Domains

[5947] It is not legal to access the same variable from different clockdomains. Instead, one may transmit data between clock domains using achannel or a port.

[5948] Channels

[5949] Channels that connect between clock domains may beuni-directional point-to-point. This means that their first use definestheir direction and the domains in which they transmit and receive. Ifone attempts to re-use the channel in a different direction or to orfrom a different clock domain the compiler generates an error. Channelsused between clock domains may be declared in one file and thenreferenced as extern in another. The timing between domains isunspecified, but the transmission is guaranteed to occur, and both sidesmay wait until the transmission has completed. For example:

[5950] //File: transmit.c

[5951] chan 8 c; // channel may have global scope

[5952] main ( )

[5953] {

[5954] int 8 x, y;

[5955] c ! x; //program may wait until data

[5956] //successfully transmitted

[5957] c ! y;

[5958] }

[5959] //File: receive.c

[5960] extern chan c;

[5961] main ( )

[5962] int 8 p, q;

[5963] c ? p;

[5964] c ? q;

Multi-file Projects

[5965] Introduction

[5966] One can combine multiple files in a single project. The projectcan have a single main function or several. If there are multiple mainfunctions within a single project, they can be loaded onto the samechip. Each main function can be associated with a different clock. Theproject can include libraries (pre-compiled Handel-C code) and blocks offoreign code (e.g. VHDL). EDIF and VHDL linking is done by synthesistools. One can refer to functions, macros and shared expressions thathave been defined in another file by prototyping them. One prototype bydeclaring an object at the top of the file in which it is used.

[5967] Function prototypes are in the following format:

[5968] returnType functionName(parameterTypeList);

[5969] Macro prototypes are like this:

[5970] macro expr Name(parameterList);

[5971] macro proc Name(parameterList);

[5972] Functions and macros may be static or extern. static functionsand macros may only be used in the file where they are defined.

[5973] One can collect all the prototypes into a single header file andthen #include it within the code files.

[5974] One can access variables declared in other files by using theextern keyword.

[5975] One cannot use variables to communicate between clock domains.Variables are restricted to a single clock domain. The only items thatcan connect across separate clock domains are channels and MPRAMs

Language Summary

[5976] Introduction

[5977] This section summarizes the previous sections by listing all theHandel-C types, statements and operators.

[5978] Type summary

[5979]FIG. 82 illustrates a table that lists the most common types thatmay be associated with a variable 8200, in accordance with oneembodiment of the present invention. FIG. 83 illustrates a table thatlists all prefixes to the above types for different architectural objecttypes 8300, in accordance with one embodiment of the present invention.

[5980] Statement Summary

[5981]FIG. 84 illustrates a table that lists all statements in theHandel-C language 8400, in accordance with one embodiment of the presentinvention. The following table lists all statements in the Handel-Clanguage. Note that the assignment group of operations and the incrementand decrement operations are included as statements to reflect the factthat Handel-C expressions cannot contain side effects.

[5982] Operator Summary

[5983]FIGS. 85A and 85B illustrate a table that lists all operators inthe Handel-C language 8500, in accordance with one embodiment of thepresent invention. In this table, entries at the top have the highestprecedence and entries at the bottom have the lowest precedence. Entrieswithin the same group have the same precedence. Note that function callsand assignments are not true operators in Handel-C.

Complete Language Syntax

[5984] Introduction

[5985] In this section of the present description, the complete Handel-Clanguage syntax may be given in BNF-like notation.

[5986] Keyword Summary

[5987]FIGS. 86A through 86E illustrate a table that lists keywords 8600,in accordance with one embodiment of the present invention. The keywordslisted below are reserved and cannot be used for any other purpose.Keywords not in ISO-C are in bold. The following character sequences arealso reserved: * */ // # ″ ′.

Complete Language Syntax

[5988] The conventions used in this language reference are:

[5989] Terminal symbols are set in typewriter font like this.

[5990] Non-terminal symbols are set in italic font like this.

[5991] Square brackets [. . . ] denote optional components.

[5992] Braces {. . . } denotes zero, one or more repetitions of theenclosed components.

[5993] Braces with a trailing plus sign {. . . } +denote one or severalrepetitions of the enclosed components.

[5994] Parentheses ( . . . ) denote grouping.

[5995] Identifiers

[5996] Identifiers are sequences of letters, digits and _, starting witha letter. All characters in an identifier are meaningful and allidentifiers are case sensitive.

[5997] identifier ::=letter {letter | 0 . . . 9}

[5998] letter ::=A . . . Z | a . . . z | _(—)

[5999] Integer Constant

[6000] integer_constant ::=[−]{1 . . . 9 }+{0 . . . 9}

[6001] | [−](0x | 0X){0 . . . 9 | A . . . F | a . . . f}+

[6002] | [−](0){0 . . . 7}

[6003] | [−](0b | 0B){0 . . . }+

[6004] Character Constants

[6005]FIG. 87A illustrates escape codes and their associated meanings8700, in accordance with one embodiment of the present invention.Character is any printable character or any of the following escapecodes.

[6006] Strings

[6007] string:=“{character}”

[6008] Floating point constants

[6009] float constant::=

[6010] [{0 . . . 9}+]. {0 . . . 9}+[(e| E)[+|−]{0 . . . 9}+][f|F|I|L]

[6011] | {0 . . . 9}+.[(e | E)[+|−]{0 . . . 9}+][f| F| I| L]

[6012] | {0 . . . 9}+(e | E)[+|−]{0 . . . 9}+[f| F| I| L]

[6013] Overview

[6014] external_declaration : function_definition

[6015] | declaration

[6016] | set_statement;

[6017] Functions and Declarations

[6018] function_definition::=declaration_specifiers declaratorcompound_statement [with initialiser,]

[6019] | declarator compound_statement [ with initialiser ;]

[6020] declaration::=declaration_specifiers [ init_declarator_list][with initialiser];

[6021] | interface_declaration

[6022] | macro_declaration

[6023] declaration_specifiers ::=storage_class_specifier [declaration_specifiers]

[6024] | type_specifier [ declaration_specifiers]

[6025] | type_qualifier [ declaration_specifiers]

[6026] storage_class_specifier ::=auto

[6027] | register

[6028] | inline

[6029] | typedef

[6030] | extern

[6031] | static

[6032] type_specifier::=void

[6033] | char

[6034] | short

[6035] | int

[6036] | long

[6037] | float

[6038] | double

[6039] | signed.

[6040] | unsigned

[6041] | typeof ( expression )

[6042] | signal_specifier

[6043] | channel_specifier

[6044] | ram_specifier

[6045] | struct_or_union_specifier

[6046] | enum_specifier

[6047] | typedef_name

[6048] type_qualifier::=const | volatile

[6049] typedef_name::=identifier

[6050] init_declarator_list ::=declarator [=initialiser] { ,declarator[=initialiser]}

[6051] Macro/shared exprs/procs

[6052] macro_declaration ::=macro_proc_decl

[6053] |macro_expr_decl

[6054] macro_proc_decl::=[static | extern] macro_proc_spec identifier

[6055] [([macro_param{, macro_param}])]

[6056] statement

[6057] [with initialiser ;]

[6058] macro_expr_decl::=[static | extern] macro_expr_spec identifier

[6059] [([macro_param{, macro_param}]

[6060] )]

[6061] |[static | extern] macro_expr_spec identifier

[6062] [([macro_param {, macro_param}] )]=let_initialiser

[6063] [with initialiser ];

[6064] macro_proc_spec=macro proc

[6065] | shared proc macro_expr_spec ::=macro expr

[6066] | shared expr

[6067] let initialiser ::=initialiser

[6068] let macro_expr_decl in let_initialiser

[6069] macro_param ::=identifier

[6070] Interfaces

[6071] interface_declaration ::=interface identifier(int_parameter_declaration

[6072] {, int_parameter_declaration}])

[6073] identifier ([assignment_expr_spec {,

[6074] assignment_expr_spec}]) [with

[6075] initialiser];

[6076] interface type_declarator

[6077] |old_style_interface_declarator

[6078] interface type declarator::=interface_identifier([int_parameter_proto

[6079] {, int_parameter_proto}])

[6080] identifier ([int_init_parameter_declaration {,

[6081] int_init_parameter_declaration}]

[6082] )

[6083] This format is deprecated but retained for compatibility reasonsold_style_interface_declarator ::=interface identifier ([

[6084] int_parameter_declaration

[6085] {, int_parameter_declaration}])

[6086] identifier ([assignment_expr_spec {,

[6087] assignment_expr_spec}])

[6088] [with initialiser];

[6089] interface ::=[static | extern] interface

[6090] int_parameter_proto::=declaration_specifiers

[6091] | declaration specifiers declarator

[6092] | declaration_specifiers abstract_declarator

[6093] | declaration specifiers width

[6094] int_(—parameter)_declaration ::=declaration_specifiers [withinitialiser]

[6095] | declaration_specifiers declarator [with initialiser]

[6096] | declaration_specifiers abstract_declarator [with initialiser]

[6097] | declaration_specifiers width [with initialiser]

[6098] int_init_parameter_declaration ::=int_parameter_declaration

[6099] | declaration_specifiers declarator [=initialiser] [withinitialiser]

[6100] assignment_expr_spec ::=assignment_expression [with initialiser]

[6101] Structures and Unions

[6102] struct_or_union_specifier aggregate_form [ identifier]{

[6103] {struct_declaration}+}

[6104] | aggregate_form identifier

[6105] aggregate_form::=struct

[6106] | union

[6107] | mpram

[6108] struct_declaration :={type_specifier | type_qualifier}+

[6109] {struct_declarator}+[with initialiser];

[6110] struct_declarator ::=declarator

[6111] | [declarator]: constant_expression

[6112] Enumerated Types

[6113] enum_specifier ::=enum [identifier] { enumerator {,[enumerator]}}

[6114] | enum identifier

[6115] enumerator::=identifier

[6116] | identifier=constant_expression

[6117] Signal specifiers

[6118] signal_specifier ::=signal <type_name>

[6119] | signal

[6120] Channel Specifiers

[6121] channel_specifier:: chan [<type_name>]

[6122] | chanin [<type_name>]

[6123] | chanout [<type_name>]

[6124] Ram Specifiers

[6125] ram_specifier ::=ram [<type_name>]

[6126] | rom [<type_name>]

[6127] | wom [<type_name>]

[6128] Declarators

[6129] declarator ::=[width] pointer direct_declarator

[6130] width ::=undefined

[6131] | primary_expression

[6132] direct_declarator ::=identifier

[6133] | (pointer direct_declarator)

[6134] | direct_declarator [[constant_expression]]

[6135] | direct_declarator ([ {parameter_declaration}+])

[6136] pointer ::=*

[6137] | *type_qualifier

[6138] | *pointer

[6139] | * type_qualifier pointer

[6140] Function Parameters

[6141] parameter_declaration ::=declaration_specifiers

[6142] | declaration_specifiers width

[6143] | declaration_specifiers abstract_declarator

[6144] | declaration_specifiers declarator

[6145] Type Names and Abstract Declarators

[6146] | type_name ::={ type_specifier | type_qualifier}+

[6147] | {type_specifier | type_qualifier}+abstract_declarator

[6148] | {type_specifier | type_qualifier}+width

[6149] abstract_declarator ::=[width] pointer direct abstract_declarator

[6150] direct_abstract_declarator::=(pointer direct_abstract_declarator)

[6151] | [direct_abstract_declarator][[constant_expression]]

[6152] | [direct_abstract_declarator] ([{parameter_declaration}+]

[6153] )

[6154] Statements

[6155] statement ::=semi_statement;

[6156] | non_semi_statement

[6157] semi_statement ::=expression_statement

[6158] | do statement while ( expression )

[6159] | jump_statement

[6160] | assert ( constant_expression [, assignment_expression{,

[6161] assignment_expression}])

[6162] | delay

[6163] | channel_statement

[6164] | set_statement

[6165] non_semi_statement::=labeled_statement

[6166] | compound_statement

[6167] | selection_statement

[6168] | iteration_statement.

[6169] The following statements can appear in for start/end conditions

[6170] for_statement ::=non_semi_statement

[6171] | expression_statement

[6172] | do statement_while (expression)

[6173] | assert ( constant_expression [, assignment_expression{,

[6174] assignment_expression)])

[6175] | delay

[6176] | channel_statement

[6177] These are the statements that can appear in prialt blocks/

[6178] prialt_statement ::=semi_statement;

[6179] | non_semi_prialt_statement

[6180] non_semi_prialt_statement ::=prialt_labeled_statement

[6181] | compound_statement

[6182] | selection_statement

[6183] | iteration_statement

[6184] labeled_statement::=identifier: statement

[6185] | case constant_expression statement

[6186] | default: statement

[6187] prialt_labeled_statement ::=identifier : prialt_statement

[6188] | case channel_statement prialt_statement

[6189] | default : prialt_statement

[6190] expression_statement ::=[expression]

[6191] channel_statement::=unary_expression ! expression

[6192] | logical_or_expression ? expression

[6193] jump_statement::=goto identifier

[6194] | continue

[6195] | break

[6196] | return

[6197] | return expression

[6198] selection_statement ::=if ( expression ) statement % prec if

[6199] | if ( expression ) statement else statement

[6200] | ifselect ( constant_expression ) statement %prec if

[6201] | ifselect ( constant_expression ) statement else statement.

[6202] | switch ( expression ) statement

[6203] | prialt {[{prialt_statement}+] }

[6204] set_statement ::=set part=STRING

[6205] | set clock=clock

[6206] | set family=identifier

[6207] | set intwidth=constant_expression

[6208] | set intwidth=undefined clock::=internal expression [withinitialiser]

[6209] | external expression [with initialiser ]

[6210] | internal_divide expression expression [with initialiser ]

[6211] | external_divide expression expression [with initialiser]

[6212] iteration_statement ::=while ( expression ) statement

[6213] | for ( [for_statement]; [expression] ; [for_statement])

[6214] statement

[6215] Compound Statements with Replicators

[6216] | compound_statement ::=[seq | par] {{declarations} {statement} }

[6217] | [seq | par| ([repl macro param{, repl_macro_param}];

[6218] constant_expression;

[6219] [repl_update_param {, repl_update_param}])

[6220] {{declaration} {statement} }

[6221] Replicator Rules

[6222] Replicator Initialisation Definitions

[6223] | repl_macro_param::=repl_param=initialiser

[6224] | ( repl_param=initialiser )

[6225] Replicator Update Definitions

[6226] repl_update_param ::=repl_update_param_body

[6227] | ( repl_update_param )

[6228] repl_update_param_body ::=repl_param assignment_operatorinitialiser

[6229] | ++repl_param

[6230] | repl_param++

[6231] | −−repl_param

[6232] | repl_param−−

[6233] repl_param ::=identifier

[6234] | ( repl_param ).

[6235] Expressions

[6236] constant_expression ::=assignment_expression

[6237] expression::=assignment_expression

[6238] | expression, assignment_expression}

[6239] assignment_expression::=conditional_expression

[6240] | unary_expression assignment_operator assignment_expression

[6241] assignment_operator ::==| *=|/=|%=|+=|−=|<<=|>>=|&=

[6242] | X|=| |=

[6243] initialiser::=assignment_expression

[6244] conditional_expression :=logical_or_expression

[6245] | logical_or_expression ? expression : conditional_expression

[6246] logical_or_expression ::=logical and expression

[6247] |logical_or_expression ∥logical_and_expression

[6248] logical_and_expression::=inclusive_or_expression on

[6249] |logical_and_expression && inclusive_or_expression

[6250] inclusive_or_expression ::=exclusive_or_expression

[6251] | inclusive_or_expression | exclusive_or_expression

[6252] exclusive or expression ::=and_expression

[6253] | exclusive_or_expression ^ and_expression

[6254] and_expression::=equality_expression

[6255] | and_expression & equality_expression

[6256] equality_expression ::=relational_expression

[6257] | equality_expression==relational_expression

[6258] | equality_expression !=relational_expression

[6259] relational_expression ::=cat_expression

[6260] | relational_expression<cat_expression

[6261] | relational_expression>cat_expression

[6262] | relational_expression<=cat_expression

[6263] |relational_expression>=cat_expression

[6264] cat_expression::=shift_expression.

[6265] |cat_expression @ shift_expression

[6266] shift_expression ::=additive_expression

[6267] | shift_expression<<additive_expression

[6268] |shift expression>>additive_expression

[6269] additive expression::=multiplicative expression

[6270] |additive_expression+multiplicative_expression

[6271] |additive_expression−multiplicative_expression

[6272] multiplicative_expression ::=take_drop_expression

[6273] |multiplicative_expression*take_drop_expression

[6274] |multiplicative_expression take_drop_expression

[6275] | multiplicative_expression % take drop_expression

[6276] take_drop_expression ::=cast_expression

[6277] |take_drop_expression<=cast_expression

[6278] | take_drop_expression \\ cast_expression

[6279] cast_expression ::=unary_expression

[6280] | ( type_name ) cast_expression

[6281] unary_expression ::=postfix_expression

[6282] | ++ unary_expression

[6283] | −− unary_expression

[6284] | unary operator cast_expression

[6285] | sizeof unary_expression

[6286] | sizeof (type_name)

[6287] |width (expression)

[6288] unary_operator ::=& | +| −| ˜| !| *

[6289] postfix_expression:: =select_expression

[6290] |postfix_expression [expression]

[6291] |postfix_expression [expression : expression]

[6292] |postfix_expression [: expression]

[6293] |postfix_expression [expression:]

[6294] |postfix_expression [ ]

[6295] |postfix_expression ([assignment_expression

[6296] {, assignment_expression}])

[6297] | postfix_expression. identifier

[6298] | postfix_expression->identifier

[6299] |postfix_expression ++.| postfix_expression−

[6300] select_expression::=primary_expression

[6301] |select (constant expression, constant_expression,

[6302] constant_expression)

[6303] primary_expression::=identifier

[6304] | constant

[6305] | (expression)

[6306] | { }

[6307] | {[initialiser {, initialiser}[, ]]}

[6308] constant::=integer_constant

[6309] |character_constant

[6310] |string_constant

[6311] integer_constant::=NUMBER

[6312] character_constant::=CHARACTER

[6313] string_constant::=STRING

[6314] Program

[6315] The overall syntax for the program is:

[6316] program::={global_declaration}

[6317] void main(void) {

[6318] {declaration}

[6319] {statement}

Preprocessor

[6320] Introduction

[6321] Handel-C is a programming language designed to enable thecompilation of programs into synchronous hardware. Handel-C is not ahardware description language though; rather it is a programminglanguage aimed at expressing algorithms from a high level.

[6322] This second describes the Handel-C preprocessor. The Handel-Ccompiler may invoke the preprocessor automatically each time it compilesa program.

[6323] The GNU Preprocessor

[6324] Handel-C does not use its own preprocessor. Rather it uses theGNU preprocessor written by the Free Software Foundation for the gcc Ccompiler. Since this section simply contains the text for the GNU CPreprocessor, not all statements may be relevant to the Handel-Ccompiler. For example, the section detailing the CPU predefined macrosdoes not apply because the Handel-C program may not be executing on aprocessor at all.

C Preprocessor

[6325] Introduction

[6326] The C preprocessor is a macro processor that is usedautomatically by the C compiler to transform the program before actualcompilation. It is called a macro processor because it allows one todefine macros, which are brief abbreviations for longer constructs.

[6327] The C preprocessor provides four separate facilities that one canuse as he or she sees fit:

[6328] Inclusion of header files. These are files of declarations thatcan be substituted into the program.

[6329] Macro expansion. One can define macros, which are abbreviationsfor arbitrary fragments of C code, and then the C preprocessor mayreplace the macros with their definitions throughout the program.

[6330] Conditional compilation. Using special preprocessing directives,one can include or exclude parts of the program according to variousconditions.

[6331] Line control. If one uses a program to combine or rearrangesource files into an intermediate file which is then compiled, he or shecan use line control to inform the compiler of where each source lineoriginally came from.

[6332] C preprocessors vary in some details. This second discusses theGNU C preprocessor, the C Compatible Compiler Preprocessor.

[6333] The GNU C preprocessor provides a superset of the features ofANSI Standard C. ANSI Standard C requires the rejection of many harmlessconstructs commonly used by today's C programs. Such incompatibilitywould be inconvenient for users, so the GNU C preprocessor is configuredto accept these constructs by default. Strictly speaking, to get ANSIStandard C, one may use the options ‘-trigraphs’, ‘-undef’ and‘-pedantic’, but in practice the consequences of having strict ANSIStandard C make it undesirable to do this.

[6334] Transformations Made Globally

[6335] Most C preprocessor features are inactive unless one givesspecific directives to request their use. But there are threetransformations that the preprocessor always makes on all the input itreceives, even in the absence of directives.

[6336] All C comments are replaced with single spaces.

[6337] Backslash-Newline sequences are deleted, no matter where. Thisfeature allows one to break long lines for cosmetic purposes withoutchanging their meaning.

[6338] Predefined macro names are replaced with their expansions.

[6339] The first two transformations are done before nearly all otherparsing and before preprocessing directives are recognized. Thus, forexample, one can split a line cosmetically with Backslash-Newlineanywhere (except when trigraphs are in use; see below).

[6340] /*

[6341] */ #/ *

[6342] * defi\

[6343] ne FO\

[6344] O 10|

[6345] 20

[6346] is equivalent to ‘#define FOO 1020’. One can split even an escapesequence with Backslash-Newline. For example, one can split “foo\bar”between the ‘\’ and the ‘b’ to get

[6347] “foo\\

[6348] bar”

[6349] This behavior is unclean: in all other contexts, a Backslash canbe inserted in a string constant as an ordinary character by writing adouble Backslash, and this creates an exception. But the ANSI C standardrequires it. (Strict ANSI C does not allow Newlines in string constants,so they do not consider this a problem.)

[6350] But there are a few exceptions to all three transformations.

[6351] C comments and predefined macro names are not recognized inside a‘#include’ directive in which the file name is delimited with ‘<’ and‘>’.

[6352] C comments and predefined macro names are never recognized withina character or string constant. (Strictly speaking, this is the rule,not an exception, but it is worth noting here anyway.)

[6353] Backslash-Newline may not safely be used within an ANSI“trigraph”. Trigraphs are converted before Backslash-Newline is deleted.If one writes what looks like a trigraph with a Backslash-Newlineinside, the Backslash-Newline is deleted as usual, but it is then toolate to recognize the trigraph.

[6354] This exception is relevant only if one use the ‘-trigraphs’option to enable trigraph processing.

[6355] Preprocessing Directives

[6356] Most preprocessor features are active only if one usespreprocessing directives to request their use. Preprocessing directivesare lines in the program that start with ‘#’. The ‘#’ is followed by anidentifier that is the directive name. For example, ‘#define’ is thedirective that defines a macro. Whitespace is also allowed before andafter the ‘#’.

[6357] The set of valid directive names is fixed. Programs cannot definenew preprocessing directives.

[6358] Some directive names require arguments; these make up the rest ofthe directive line and may be separated from the directive name bywhitespace. For example, ‘#define’ may be followed by a macro name andthe intended expansion of the macro.

[6359] A preprocessing directive cannot be more than one line in normalcircumstances. It may be split cosmetically with Backslash-Newline, butthat has no effect on its meaning. Comments containing Newlines can alsodivide the directive into multiple lines, but the comments are changedto Spaces before the directive is interpreted. The only way asignificant Newline can occur in a preprocessing directive is within astring constant or character constant. Note that most C compilers thatmight be applied to the output from the preprocessor do not acceptstring or character constants containing Newlines.

[6360] The ‘#’ and the directive name cannot come from a macroexpansion. For example, if ‘foo’ is defined as a macro expanding to‘define’, that does not make ‘#foo’ a valid preprocessing directive.

Header Files

[6361] Introduction

[6362] A header file is a file containing C declarations and macrodefinitions to be shared between several source files. A person mayrequest the use of a header file in the program with the C preprocessingdirective ‘#include’.

[6363] Uses of Header Files

[6364] Header files serve two kinds of purposes.

[6365] System header files declare the interfaces to parts of theoperating system. A person may include them in the program to supply thedefinitions and declarations he or she needs to invoke system calls andlibraries.

[6366] The header files contain declarations for interfaces between thesource files of the program. Each time a person has a group of relateddeclarations and macro definitions all or most of which are needed inseveral different source files, it is a good idea to create a headerfile for them.

[6367] Including a header file produces the same results in Ccompilation as copying the header file into each source file that needsit. But such copying would be time-consuming and error-prone. With aheader file, the related declarations appear in only one place. If theyneed to be changed, they can be changed in one place, and programs thatinclude the header file may automatically use the new version when nextrecompiled. The header file eliminates the labor of finding and changingall the copies as well as the risk that a failure to find one copy mayresult in inconsistencies within a program.

[6368] The usual convention is to give header files names that end with‘.h’. Avoid unusual characters in header file names, as they reduceportability.

[6369] The ‘#include’ Directive

[6370] Both user and system header files are included using thepreprocessing directive ‘#include’. It has three variants:

[6371] #include <file>

[6372] This variant is used for system header files. It searches for afile named file in a list of directories specified by you, then in astandard list of system directories. One may specify directories tosearch for header files with the command option ‘-I’. The option‘-nostdinc’ inhibits searching the standard system directories; in thiscase only the directories one specifies are searched. The parsing ofthis form of ‘#include’ is slightly special because comments are notrecognized within the ‘<. . . >’. Thus, in ‘#include <x/*y>’ the ‘/*’does not start a comment and the directive specifies inclusion of asystem header file named ‘x/*y’. Of course, a header file with such aname is unlikely to exist on Unix, where shell wildcard features wouldmake it hard to manipulate. The argument file may not contain a ‘<’character. It may, however, contain a ‘>’ character.

[6373] #include “file”

[6374] This variant is used for header files of the program. It searchesfor a file named file first in the current directory, then in the samedirectories used for system header files. The current directory is thedirectory of the current input file. It is tried first because it ispresumed to be the location of the files that the current input filerefers to. (If the ‘-I-’ option is used, the special treatment of thecurrent directory is inhibited.)

[6375] The argument file may not contain “ ” characters. If backslashesoccur within file, they are considered ordinary text characters, notescape characters. None of the character escape sequences appropriate tostring constants in C are processed. Thus, ‘#include “x\n\\y”’ specifiesa filename containing three backslashes. It is not clear why thisbehavior is ever useful, but the ANSI standard specifies it.

[6376] #include anything else

[6377] This variant is called a computed #include. Any ‘#include’directive whose argument does not fit the above two forms is a computedinclude. The text anything else is checked for macro calls, which areexpanded. When this is done, the result may fit one of the above twovariants - in particular, the expanded text may in the end be surroundedby either quotes or angle braces.

[6378] This feature allows one to define a macro which controls the filename to be used at a later point in the program. One application of thisis to allow a site-specific configuration file for the program tospecify the names of the system include files to be used. This can helpin porting the program to various operating systems in which thenecessary system header files are found in different places.

[6379] How ‘#include’ Works

[6380] The ‘#include’ directive works by directing the C preprocessor toscan the specified file as input before continuing with the rest of thecurrent file. The output from the preprocessor contains the outputalready generated, followed by the output resulting from the includedfile, followed by the output that comes from the text after the‘#include’ directive. For example, given a header file ‘header.h’ asfollows,

[6381] char *test ( );

[6382] and a main program called ‘program.c’ that uses the header file,like this,

[6383] int x;

[6384] #include “header.h”

[6385] main( )

[6386] {

[6387] printf (test ( );

[6388] }

[6389] the output generated by the C preprocessor for ‘program.c’ asinput would be

[6390] int x;

[6391] char *test ( );

[6392] main( )

[6393] {

[6394] printf (test ( ));

[6395] }

[6396] Included files are not limited to declarations and macrodefinitions; those are merely the typical uses. Any fragment of a Cprogram can be included from another file. The include file could evencontain the beginning of a statement that is concluded in the containingfile, or the end of a statement that was started in the including file.However, a comment or a string or character constant may not start inthe included file and finish in the including file. An unterminatedcomment, string constant or character constant in an included file isconsidered to end (with an error message) at the en d of the file.

[6397] It is possible for a header file to begin or end a syntactic unitsuch as a function definition, but that would be very confusing, sodon't do it.

[6398] The line following the ‘#include’ directive is always treated asa separate line by the C preprocessor even if the included file lacks afinal newline.

[6399] Once-Only Include Files

[6400] Very often, one header file includes another. It can easilyresult that a certain header file is included more than once. This maylead to errors, if the header file defines structure types or typedefs,and is certainly wasteful. Therefore, it is often desired to preventmultiple inclusion of a header file.

[6401] The standard way to do this is to enclose the entire realcontents of the file in a conditional, like this:

[6402] #ifndef FILE_FOO_SEEN

[6403] #define FILE_FOO_SEEN

[6404] the entire file

[6405] #endif /* FILE_FOO_SEEN */

[6406] The macro FILE_FOO_SEEN indicates that the file has been includedonce already. In a user header file, the macro name should not beginwith ‘_’. In a system header file, this name should begin with ‘_’ toavoid conflicts with user programs. In any kind of header file, themacro name should contain the name of the file and some additional text,to avoid conflicts with other header files.

[6407] The GNU C preprocessor is programmed to notice when a header fileuses this particular construct and handle it efficiently. If a headerfile is contained entirely in a ‘#ifndef’ conditional, then it recordsthat fact. If a subsequent ‘#include’ specifies the same file, and themacro in the ‘#ifndef’ is already defined, then the file is entirelyskipped, without even reading it.

[6408] There is also an explicit directive to tell the preprocessor thatit need not include a file more than once. This is called ‘#pragmaonce’, and was used in addition to the ‘#ifndef’ conditional around thecontents of the header file. ‘#pragma once’ is now obsolete and shouldnot be used at all.

[6409] In the Objective C language, there is a variant of ‘#include’called ‘#import’ which includes a file, but does so at most once. If oneuses ‘#import’ instead of ‘#include’, then he or she doesn't need theconditionals inside the header file to prevent multiple execution of thecontents. ‘#import’ is obsolete because it is not a well designedfeature. It requires the users of a header file—the applicationsprogrammers—to know that a certain header file should only be includedonce. It is much better for the header file's implementor to write thefile so that users don't need to know this. Using ‘#ifndef’ accomplishesthis goal.

[6410] Inheritance and Header Files

[6411] Inheritance is what happens when one object or file derives someof its contents by virtual copying from another object or file. In thecase of C header files, inheritance means that one header file includesanother header file and then replaces or adds something.

[6412] If the inheriting header file and the base header file havedifferent names, then inheritance is straightforward: simply write‘#include “base”’ in the inheriting file.

[6413] Sometimes it is necessary to give the inheriting file the samename as the base file. This is less straightforward.

[6414] For example, suppose an application program uses the systemheader file ‘sys/signal.h’, but the version of‘usr/include/sys/signal.h’on a particular system doesn't do what the application program expects.It might be convenient to define a “local” version, perhaps under thename ‘/usr/local/include/sys/signal.h’, to override or add to the onesupplied by the system.

[6415] One can do this by using the option ‘-I.’ for compilation, andwriting a file ‘sys/signal.h’ that does what the application programexpects. But making this file include the standard ‘sys/signal.h’ is notso easy—writing ‘#include <sys/signal.h>’ in that file doesn't work,because it includes the version of the file, not the standard systemversion. Used in that file itself, this leads to an infinite recursionand a fatal error in compilation.

[6416] ‘#include </usr/include/sys/signal.h>’ would find the properfile, but that is not clean, since it makes an assumption about wherethe system header file is found. This is bad for maintenance, since itmeans that any change in where the system's header files are keptrequires a change somewhere else.

[6417] The clean way to solve this problem is to use ‘#include_next’,which means, “Include the next file with this name.” This directiveworks like ‘#include’ except in searching for the specified file: itstarts searching the list of header file directories after the directoryin which the current file was found.

[6418] Suppose one specify ‘-I /usr/local/include’, and the list ofdirectories to search also includes ‘/usr/include’; and suppose thatboth directories contain a file named ‘sys/signal.h’. Ordinary ‘#include<sys/signal.h>’ finds the file under ‘/usr/local/include’. If that filecontains ‘#include_next <sys/signal.h>’, it starts searching after thatdirectory, and finds the file in ‘/usr/include’..4. Macros

[6419] Introduction

[6420] A macro is a sort of abbreviation which one can define once andthen use later. There are many complicated features associated withmacros in the C preprocessor.

[6421] Simple Macros

[6422] A simple macro is a kind of abbreviation. It is a name whichstands for a fragment of code. Some people refer to these as manifestconstants.

[6423] Before one can use a macro, he or she may define it explicitlywith the ‘#define’ directive. ‘#define’ is followed by the name of themacro and then the code it should be an abbreviation for. For example,

[6424] #define BUFFER_SIZE 1020

[6425] defines a macro named ‘BUFFER_SIZE’ as an abbreviation for thetext ‘1020’. If somewhere after this ‘#define’ directive there comes a Cstatement of the form

[6426] foo=(char *) xmalloc (BUFFER_SIZE);

[6427] then the C preprocessor may recognize and expand the macro‘BUFFER_SIZE’, resulting in

[6428] foo=(char *) xmalloc (1020);

[6429] The use of all upper case for macro names is a standardconvention. Programs are easier to read when it is possible to tell at aglance which names are macros. Normally, a macro definition may be asingle line. like all C preprocessing directives. (One can split a longmacro definition cosmetically with Backslash-Newline.) There is oneexception: Newlines can be included in the macro definition if within astring or character constant. This is because it is not possible for amacro definition to contain an unbalanced quote character; thedefinition automatically extends to include the matching quote characterthat ends the string or character constant. Comments within a macrodefinition may contain Newlines, which make no difference since thecomments are entirely replaced with Spaces regardless of their contents.

[6430] Aside from the above, there is no restriction on what can go in amacro body. Parentheses need not balance. The body need not resemblevalid C code. (But if it does not, one may get error messages from the Ccompiler when one uses the macro.)

[6431] The C preprocessor scans the program sequentially, so macrodefinitions take effect at the place write them. Therefore, thefollowing input to the C preprocessor:

[6432] foo=X;

[6433] #define X 4

[6434] bar=X;

[6435] produces as output foo=X;

[6436] bar=4;

[6437] After the preprocessor expands a macro name, the macro'sdefinition body is appended to the front of the remaining input, and thecheck for macro calls continues. Therefore, the macro body can containcalls to other macros. For example, after

[6438] #define BUFSIZE 1020

[6439] #define TABLESIZE BUFSIZE

[6440] the name ‘TABLESIZE’ when used in the program would go throughtwo stages of expansion, resulting ultimately in ‘1020’. This is not atall the same as defining ‘TABLESIZE’ to be ‘1020’. The ‘#define’ for‘TABLESIZE’ uses exactly the body one specify—in this case,‘BUFSIZE’—and does not check to see whether it too is the name of amacro. It's only when one uses ‘TABLESIZE’ that the result of itsexpansion is checked for more macro names.

[6441] Macros with Arguments

[6442] A simple macro always stands for exactly the same text, each timeit is used. Macros can be more flexible when they accept arguments.Arguments are fragments of code that one supplies each time the macro isused. These fragments are included in the expansion of the macroaccording to the directions in the macro definition. A macro thataccepts arguments is called a function-like macro because the syntax forusing it looks like a function call. To define a macro that usesarguments, one writes a ‘#define’ directive with a list of argumentnames in parentheses after the name of the macro. The argument names maybe any valid C identifiers, separated by commas and optionallywhitespace The open parenthesis may follow the macro name immediately,with no space in between.

[6443] For example, here is a macro that computes the minimum of twonumeric values, as it is defined in many C programs:

[6444] #define min(X, Y) ((X)<(Y) ? (X): (Y))

[6445] To use a macro that expects arguments, one writes the name of themacro followed by a list of actual arguments in parentheses, separatedby commas. The number of actual arguments one gives may match the numberof arguments the macro expects. Examples of use of the macro ‘min’include ‘min (1, 2)’ and ‘min (x+28, *p)’.

[6446] The expansion text of the macro depends on the arguments a personuses. Each of the argument names of the macro is replaced, throughoutthe macro definition, with the corresponding actual argument. Using thesame macro ‘min’ defined above, ‘min (1, 2)’ expands into (1)<(2) ? (1):(2)) where ‘1’ has been substituted for ‘X’ and ‘2’for ‘Y’. Likewise,‘min (x+28, *p)’ expands into.

[6447] ((x+28)<(*p) ? (x+28): (*p))

[6448] Parentheses in the actual arguments may balance; a comma withinparentheses does not end an argument. However, there is no requirementfor brackets or braces to balance, and they do not prevent a comma fromseparating arguments. Thus, macro (array[x =y, x+1]) passes twoarguments to macro: ‘array[x=y’ and ‘x+1]’. If one wants to supply‘array[x=y,x+1]’ as an argument, one may write it as ‘array[(x=y,x+1)]’, which is equivalent C code.

[6449] After the actual arguments are substituted into the macro body,the entire result is appended to the front of the remaining input, andthe check for macro calls continues. Therefore, the actual arguments cancontain calls to other macros, either with or without arguments, or evento the same macro. The macro body can also contain calls to othermacros. For example, ‘min (min (a, b), c)’ expands into this text:

[6450] ((((a)<(b) ? (a) : (b)))<(c)

[6451] ? (((a)<(b) ? (a) : (b)))

[6452] : (c))

[6453] (Line breaks shown here for clarity would not actually begenerated.) If a macro foo takes one argument, and one wants to supplyan empty argument, he or she may write at least some whitespace betweenthe parentheses, like this: ‘foo ( )’. Just ‘foo ( )’ is providing noarguments, which is an error if foo expects an argument. But ‘foo( ) ()’ is the correct way to call a macro defined to take zero arguments,like this:

[6454] #define foo( ) ( )

[6455] If one uses the macro name followed by something other than anopen-parenthesis (after ignoring any spaces, tabs and comments thatfollow), it is not a call to the macro, and the preprocessor does notchange what he or she has written. Therefore, it is possible for thesame name to be a variable or function in the program as well as amacro, and one can choose in each instance whether to refer to the macro(if an actual argument list follows) or the variable or function (if anargument list does not follow).

[6456] Such dual use of one name could be confusing and should beavoided except when the two meanings are effectively synonymous: thatis, when the name is both a macro and a function and the two havesimilar effects. One can think of the name simply as a function; use ofthe name for purposes other than calling it (such as, to take theaddress) may refer to the function, while calls may expand the macro andgenerate better but equivalent code. For example, one can use a functionnamed ‘min’ in the same source file that defines the macro. If onewrites ‘&min’ with no argument list, one refers to the function. If onewrites ‘min (x, bb)’, with an argument list, the macro is expanded. Ifone writes ‘(min) (a, bb)’, where the name ‘min’ is not followed by anopen-parenthesis, the macro is not expanded, so one winds up with a callto the function ‘min’.

[6457] One may not define the same name as both a simple macro and amacro with arguments. In the definition of a macro with arguments, thelist of argument names may follow the macro name immediately with nospace in between. If there is a space after the macro name, the macro isdefined as taking no arguments, and all the rest of the line is taken tobe the expansion. The reason for this is that it is often useful todefine a macro that takes no arguments and whose definition begins withan identifier in parentheses. This rule about spaces makes it possiblefor one to do either this:

[6458] #define FOO(x)−1/ (x)

[6459] (which defines ‘FOO’ to take an argument and expand into minusthe reciprocal of that argument) or this:

[6460] #define BAR (x)−1/ (x).

[6461] (which defines ‘BAR’ to take no argument and always expand into‘(x)−1 /(x)’).

[6462] Note that the uses of a macro with arguments can have spacesbefore the left parenthesis; it's the definition where it matterswhether there is a space.

[6463] Predefined Macros

[6464] Several simple macros are predefined. One can use them withoutgiving definitions for them. They fall into two classes: standard macrosand system-specific macros.

[6465] Standard Predefined Macros

[6466] The standard predefined macros are available with the samemeanings regardless of the machine or operating system on which one isusing GNU C. Their names all start and end with double underscores.Those preceding_GNUC_in this table are standardized by ANSI C; the restare GNU C extensions.

[6467] _FILE_

[6468] This macro expands to the name of the current input file, in theform of a C string constant. The precise name returned is the one thatwas specified in ‘#include’ or as the input file name argument.

[6469] _LINE_

[6470] This macro expands to the current input line number, in the formof a decimal integer constant. While one can call it a predefined macro,it's a pretty strange macro, since its “definition” changes with eachnew line of source code. This and ‘_FILE_’ are useful in generating anerror message to report an inconsistency detected by the program; themessage can state the source line at which the inconsistency wasdetected. For example,

[6471] fprintf (stderr, “Internal error:”

[6472] “negative string length”

[6473] “%d at %s, line %d.”,

[6474] length, _FILE_, _LINE_;

[6475] ‘#include’ directive changes the expansions of ‘_FILE_’ and‘_LINE_’ to correspond to the included file. At the end of that file,when processing resumes on the input file that contained the ‘#include’directive, the expansions of ‘_FILE_’ and ‘_LINE_’ revert to the valuesthey had before the ‘#include’ (but ‘_LINE_’ is then incremented by oneas processing moves to the line after the ‘#include’).

[6476] The expansions of both ‘_FILE_’ and ‘_LINE_’ are altered if a‘#line’ directive is used.

[6477] _DATE_(—)

[6478] This macro expands to a string constant that describes the dateon which the preprocessor is being run. The string constant containseleven characters and looks like ‘“Jan. 29 1987”’ or ‘“Apr. 1 1905”’.

[6479] _TIME_(—)

[6480] This macro expands to a string constant that describes the timeat which the preprocessor is being run. The string constant containseight characters and looks like

[6481] ‘“23:59:01”’.

[6482] _STDC_(—)

[6483] This macro expands to the constant 1, to signify that this isANSI Standard C. (Whether that is actually true depends on what Ccompiler may operate on the output from the preprocessor.)

[6484] _STDC_VERSION_(—)

[6485] This macro expands to the C Standard's version number, a longinteger constant of the form ‘yyyymmL’ where yyyy and mm are the yearand month of the Standard version. This signifies which version of the CStandard the preprocessor conforms to. Like ‘_STDC_’, whether thisversion number is accurate for the entire implementation depends on whatC compiler may operate on the output from the preprocessor.

[6486] _GNUC_(—)

[6487] This macro is defined if and only if this is GNU C. This macro isdefined only when the entire GNU C compiler is in use; if one invokesthe preprocessor directly, ‘_GNUC_’ is undefined.

[6488] The value identifies the major version number of GNU CC (‘1’ forGNU CC version 1, which is now obsolete, and ‘2’ for version 2).

[6489] _GNUC_MINOR_(—)

[6490] The macro contains the minor version number of the compiler. Thiscan be used to work around differences between different releases of thecompiler (for example, if gcc 2.6.3 is known to support a feature, onecan test for _GNUC_(—)>2 ∥ (_GNUC_(—)==2 && _GNUC_MINOR_(—)>=6)). Thelast number, ‘3’ in the example above, denotes the bugfix level of thecompiler; no macro contains this value.

[6491] _GNUG_(—)

[6492] The GNU C compiler defines this when the compilation language isC++; use ‘_GNUG_’ to distinguish between GNU C and GNU C++.

[6493] _cplusplus

[6494] The draft ANSI standard for C++ used to require predefining thisvariable. Though it is no longer required, GNU C++ continues to defineit, as do other popular C++ compilers. One can use ‘_cplusplus’ to testwhether a header is compiled by a C compiler or a C++ compiler.

[6495] _STRICT_ANSI_(—)

[6496] This macro is defined if and only if the ‘-ansi’ switch wasspecified when GNU C was invoked. Its definition is the null string.This macro exists primarily to direct certain GNU header files not todefine certain traditional Unix constructs which are incompatible withANSI C.

[6497] _BASE_FILE_(—)

[6498] This macro expands to the name of the main input file, in theform of a C string constant. This is the source file that was specifiedas an argument when the C compiler was invoked.

[6499] _INCLUDE_LEVEL_(—)

[6500] This macro expands to a decimal integer constant that representsthe depth of nesting in include files. The value of this macro isincremented on every ‘#include’ directive and decremented at every endof file. For input files specified by command line arguments, thenesting level is zero.

[6501] _VERSION_(—)

[6502] This macro expands to a string which describes the version numberof GNU C. The string is normally a sequence of decimal numbers separatedby periods, such as ‘“2.6.0”’.

[6503] The only reasonable use of this macro is to incorporate it into astring constant.

[6504] _OPTIMIZE_(—)

[6505] This macro is defined in optimizing compilations. It causescertain GNU header files to define alternative macro definitions forsome system library functions. It is unwise to refer to or test thedefinition of this macro unless one makes very sure that programs mayexecute with the same effect regardless.

[6506] _CHAR_UNSIGNED_(—)

[6507] This macro is defined if and only if the data type char isunsigned on the target machine. It exists to cause the standard headerfile ‘limit.h’ to work correctly. It is bad practice to refer to thismacro; instead, it is best to refer to the standard macros defined in‘limit.h’. The preprocessor uses this macro to determine whether or notto sign-extend large character constants written in octal.

[6508] _REGISTER_PREFIX

[6509] This macro expands to a string describing the prefix applied tocpu registers in assembler code. It can be used to write assembler codethat is usable in multiple environments. For example, in the ‘m68k-aout’environment it expands to the string ‘“ ”’, but in the ‘m68k-coff’environment it expands to the string ‘“%”’.

[6510] _USER_LABEL_PREFIX_(—)

[6511] This macro expands to a string describing the prefix applied touser generated labels in assembler code. It can be used to writeassembler code that is usable in multiple environments. For example, inthe ‘m68k-aout’ environment it expands to the string ‘“_”’, but in the‘m68k-coff’ environment it expands to the string ‘“ ”’.

[6512] Nonstandard Predefined Macros

[6513] The C preprocessor normally has several predefined macros thatvary between machines because their purpose is to indicate what type ofsystem and machine is in use. This description, being for all systemsand machines, cannot tell one exactly what their names are; instead, alist of some typical ones is offered One can use ‘cpp -dM’ to see thevalues of predefined macros.

[6514] Some nonstandard predefined macros describe the operating systemin use, with more or less specificity. For example, unix ‘unix’ isnormally predefined on all Unix systems.

[6515] BSD

[6516] ‘BSD’ is predefined on recent versions of Berkeley Unix. Othernonstandard predefined macros describe the kind of CPU, with more orless specificity. For example,

[6517] vax

[6518] ‘vax’ is predefined on Vax computers.

[6519] mc68000

[6520] ‘mc68000’ is predefined on most computers whose CPU is a Motorola68000, 68010 or 68020.

[6521] m68k

[6522] ‘m68k’ is also predefined on most computers whose CPU is a 68000,68010 or 68020; however, some makers use ‘mc68000’ and some use ‘m68k’.Some predefine both names. What happens in GNU C depends on the systemone is using it on.

[6523] M68020

[6524] ‘M68020’ has been observed to be predefined on some systems thatuse 68020 CPUs—in addition to ‘mc68000’ and ‘m68k’, which are lessspecific.

[6525] _AM29K,_AM29000

[6526] Both ‘_AM29K’ and ‘_AM29000’ are predefined for the AMD 29000 CPUfamily.

[6527] ns32000

[6528] ‘ns32000’ is predefined on computers which use the NationalSemiconductor 32000 series CPU. Yet other nonstandard predefined macrosdescribe the manufacturer of the system. For example,

[6529] sun

[6530] ‘sun’ is predefined on all models of Sun computers.

[6531] Pyr

[6532] ‘pyr’ is predefined on all models of Pyramid computers.

[6533] Sequent

[6534] ‘sequent’ is predefined on all models of Sequent computers.

[6535] These predefined symbols are not only nonstandard, they arecontrary to the ANSI standard because their names do not start withunderscores. Therefore, the option ‘-ansi’ inhibits the definition ofthese symbols.

[6536] This tends to make ‘-ansi’ useless, since many programs depend onthe customary nonstandard predefined symbols. Even system header filescheck them and may generate incorrect declarations if they do not findthe names that are expected. One might think that the header filessupplied for the Uglix computer would not need to test what machine theyare running on, because they can simply assume it is the Uglix; butoften they do, and they do so using the customary names. As a result,very few C programs may compile with ‘-ansi’. It is intended to avoidsuch problems on the GNU system.

[6537] What, then, should one do in an ANSI C program to test the typeof machine it may run on? GNU C offers a parallel series of symbols forthis purpose, whose names are made from the customary ones by adding ‘_’at the beginning and end. Thus, the symbol _vax_would be available on aVax, and so on.

[6538] The set of nonstandard predefined names in the GNU C preprocessoris controlled (when cpp is itself compiled) by the macro‘CPP_PREDEFINES’, which should be a string containing ‘-D’ options,separated by spaces. For example, on the Sun 3, use the followingdefinition is used:

[6539] #define CPP_PREDEFINES “-Dmc68000 -Dsun -Dunix -Dm68k”

[6540] This macro is usually specified in ‘tm.h’.

[6541] Stringification

[6542] Stringification means turning a code fragment into a stringconstant whose contents are the text for the code fragment. For example,stringifying ‘foo (z)’ results in ‘“foo (z)”’.

[6543] In the C preprocessor, stringification is an option availablewhen macro arguments are substituted into the macro definition. In thebody of the definition, when an argument name appears, the character ‘#’before the name specifies stringification of the corresponding actualargument when it is substituted at that point in the definition. Thesame argument may be substituted in other places in the definitionwithout stringification if the argument name appears in those placeswith no‘#’.

[6544] Here is an example of a macro definition that usesstringification:

[6545] #define WARN_IF(EXP) \

[6546] do { if (EXP) \

[6547] fprintf (stderr, “Warning: ” #EXP “\n”); } \

[6548] while (0)

[6549] Here the actual argument for ‘EXP’ is substituted once as given,into the ‘if’ statement, and once as stringified, into the argument to‘fprintf’. The ‘do’ and ‘while (0)’ are a kludge to make it possible towrite ‘WARN_IF (arg);’, which the resemblance of ‘WARN_IF’ to a functionwould make C programmers want to do.

[6550] The stringification feature is limited to transforming one macroargument into one string constant: there is no way to combine theargument with other text and then stringify it all together. But theexample above shows how an equivalent result can be obtained in ANSIStandard C using the feature that adjacent string constants areconcatenated as one string constant. The preprocessor stringifies theactual value of ‘EXP’ into a separate string constant, resulting in textlike.

[6551] do { if(x==0) \

[6552] fprintf (stderr, “Warning: ” “x==0” “\n”); } \

[6553] while (0)

[6554] but the C compiler then sees three consecutive string constantsand concatenates them into one, producing effectively

[6555] do {if(x==0) \

[6556] fprintf (stderr, “Warning: x==0\n”); } \

[6557] while (0)

[6558] Stringification in C involves more than putting doublequotecharacters around the fragment; it is necessary to put backslashes infront of all doublequote characters, and all backslashes in string andcharacter constants, in order to get a valid C string constant with theproper contents. Thus, stringifying ‘p=“foo\n”;’ results in‘“p=\”foo\\n\“;”’. However, backslashes that are not inside of string orcharacter constants are not duplicated: ‘\n’ by itself stringifies to‘“\n”’. Whitespace (including comments) in the text being stringified ishandled according to precise rules. All leading and trailing whitespaceis ignored. Any sequence of whitespace in the middle of the text isconverted to a single space in the stringified result.

[6559] Concatenation

[6560] Concatenation means joining two strings into one. In the contextof macro expansion, concatenation refers to joining two lexical unitsinto one longer one. Specifically, an actual argument to the macro canbe concatenated with another actual argument or with fixed text toproduce a longer name. The longer name might be the name of a function,variable or type, or a C keyword; it might even be the name of anothermacro, in which case it may be expanded.

[6561] When one defines a macro, he or she requests concatenation withthe special operator ‘##’ in the macro body. When the macro is called,after actual arguments are substituted, all ‘##’ operators are deleted,and so is any whitespace next to them (including whitespace that waspart of an actual argument). The result is to concatenate the syntactictokens on either side of the ‘##’.

[6562] Consider a C program that interprets named commands. Thereprobably needs to be a table of commands, perhaps an array of structuresdeclared as follows:

[6563] struct command

[6564] {

[6565] char *name;

[6566] void (*function) ( );

[6567] };

[6568] struct command commands[ ]

[6569] {

[6570] { “quit”, quit_command},

[6571] { “help”, help_command},

[6572] . . .

[6573] };

[6574] It would be cleaner not to have to give each command name twice,once in the string constant and once in the function name. A macro whichtakes the name of a command as an argument can make this unnecessary.The string constant can be created with stringification, and thefunction name by concatenating the argument with ‘_command’. Here is howit is done:

[6575] #define COMMAND(NAME) {#NAME, NAME ##_command)}

[6576] struct command commands[ ]=

[6577] {

[6578] COMMAND (quit),

[6579] COMMAND (help),

[6580] . . .

[6581] };

[6582] The usual case of concatenation is concatenating two names (or aname and a number) into a longer name. But this isn't the only validcase. It is also possible to concatenate two numbers (or a number and aname, such as ‘1.5’ and ‘e3’) into a number. Also, multicharacteroperators such as ‘+=’ can be formed by concatenation. In some cases itis even possible to piece together a string constant. However, twopieces of text that don't together form a valid lexical unit cannot beconcatenated. For example, concatenation with ‘x’ on one side and ‘+’ onthe other is not meaningful because those two characters can't fittogether in any lexical unit of C. The ANSI standard says that suchattempts at concatenation are undefined, but in the GNU C preprocessorit is well defined: it puts the ‘x’ and ‘+’ side by side with noparticular special results. Keep in mind that the C preprocessorconverts comments to whitespace before macros are even considered.Therefore, one cannot create a comment by concatenating ‘/’ and ‘*’: the‘/*’ sequence that starts a comment is not a lexical unit, but ratherthe beginning of a “long” space character. Also, one can freely usecomments next to a ‘##’ in a macro definition, or in actual argumentsthat may be concatenated, because the comments may be converted tospaces at first sight, and concatenation may later discard the spaces.

[6583] Undefining Macros

[6584] To undefine a macro means to cancel its definition. This is donewith the ‘#undef’ directive. ‘#undef’ is followed by the macro name tobe undefined.

[6585] Like definition, undefinition occurs at a specific point in thesource file, and it applies starting from that point. The name ceases tobe a macro name, and from that point on it is treated by thepreprocessor as if it had never been a macro name.

[6586] For example,

[6587] #define FOO 4

[6588] x=FOO;

[6589] #undef FOO

[6590] x=FOO;

[6591] expands into

[6592] x=4;

[6593] x=FOO;

[6594] In this example, ‘FOO’ had better be a variable or function aswell as (temporarily) a macro, in order for the result of the expansionto be valid C code.

[6595] The same form of ‘#undef’ directive may cancel definitions witharguments or definitions that don't expect arguments. The ‘#undef’directive has no effect when used on a name not currently defined as amacro.

[6596] Redefining Macros

[6597] Redefining a macro means defining (with ‘#define’) a name that isalready defined as a macro. A redefinition is trivial if the newdefinition is transparently identical to the old one. One probablywouldn't deliberately write a trivial redefinition, but they can happenautomatically when a header file is included more than once, so they areaccepted silently and without effect. Nontrivial redefinition isconsidered likely to be an error, so it provokes a warning message fromthe preprocessor. However, sometimes it is useful to change thedefinition of a macro in mid-compilation. One can inhibit the warning byundefining the macro with ‘#undef’ before the second definition. Inorder for a redefinition to be trivial, the new definition may exactlymatch the one already in effect, with two possible exceptions:

[6598] Whitespace may be added or deleted at the beginning or the end.Whitespace may be changed in the middle (but not inside strings).However, it may not be eliminated entirely, and it may not be addedwhere there was no whitespace at all. Recall that a comment counts aswhitespace.

[6599] Pitfalls and Subtleties of Macros

[6600] In this section, some special rules are described that apply tomacros and macro expansion, and point out certain cases in which therules have counterintuitive consequences that one may watch out for.

[6601] Improperly Nested Constructs

[6602] Recall that when a macro is called with arguments, the argumentsare substituted into the macro body and the result is checked, togetherwith the rest of the input file, for more macro calls. It is possible topiece together a macro call coming partially from the macro body andpartially from the actual arguments. For example,

[6603] #define double(x) (2*(x))

[6604] #define call_with_(—)1(x) x(1)

[6605] would expand ‘call_with_I (double)’ into ‘(2*(1))’. Macrodefinitions do not have to have balanced parentheses. By writing anunbalanced open parenthesis in a macro body, it is possible to create amacro call that begins inside the macro body but ends outside of it. Forexample,

[6606] #define strange(file) fprintf (file, “%s %d”,

[6607] strange(stderr) p, 35)

[6608] This bizarre example expands to ‘fprintf (stderr, “%s %d”, p,35)’!

[6609] Unintended Grouping of Arithmetic

[6610] One may have noticed that in most of the macro definitionexamples shown above, each occurrence of a macro argument name hadparentheses around it. In addition, another pair of parentheses usuallysurround the entire macro definition. Here is why it is best to writemacros that way.

[6611] Suppose one defines a macro as follows,

[6612] #define ceil_div(x, y) (x+y -1) / y

[6613] whose purpose is to divide, rounding up. (One use for thisoperation is to compute how many ‘int’ objects are needed to hold acertain number of ‘char’ objects.) Then suppose it is used as follows:

[6614] a=ceil_div (b & c, sizeof (int));

[6615] This expands into

[6616] a=(b & c+sizeof (int)−1) / sizeof

[6617] (int);

[6618] which does not do what is intended. The operator-precedence rulesof C make it equivalent to this:

[6619] a=(b & (c+sizeof(int)−1)) /

[6620] sizeof(int);

[6621] But what is desired is this:

[6622] a=((b & c)+sizeof(int)−1)) / sizeof(int),

[6623] Defining the macro as

[6624] #define ceil_div(x, y) ((x)+(y)−1)/(y) provides the desiredresult. However, unintended grouping can result in another way. Consider‘sizeof ceil div(1, 2)’. That has the appearance of a C expression thatwould compute the size of the type of ‘ceil_div (1, 2)’, but in fact itmeans something very different. Here is what it expands to:

[6625] sizeof ((1)+(2)−1)/(2)

[6626] This would take the size of an integer and divide it by two. Theprecedence rules have put the division outside the ‘sizeof’ when it wasintended to be inside. Parentheses around the entire macro definitioncan prevent such problems. Here, then, is the recommended way to define

[6627] ‘ceil_div’:

[6628] #define ceil_div(x, y) (((x)+(y)−1)/

[6629] (y))

[6630] Swallowing the Semicolon

[6631] Often it is desirable to define a macro that expands into acompound statement. Consider, for example, the following macro, thatadvances a pointer (the argument ‘p’ says where to find it) acrosswhitespace characters:

[6632] #define SKIP_SPACES (p, limit) \

[6633] { register char *lim=(limit); \

[6634] while (p !-lim) { \

[6635] if (*p++ !=‘ ’) { \

[6636] p−−; break; }}}

[6637] Here Backslash-Newline is used to split the macro definition,which may be a single line, so that it resembles the way such C codewould be laid out if not part of a macro definition. A call to thismacro might be ‘SKIP_SPACES (p, lim)’. Strictly speaking, the callexpands to a compound statement, which is a complete statement with noneed for a semicolon to end it. But it looks like a function call. So itminimizes confusion if one can use it.

[6638] like a function call, writing a semicolon afterward, as in

[6639] ‘SKIP_SPACES (p, lim);’

[6640] But this can cause trouble before ‘else’ statements, because thesemicolon is actually a null statement. Suppose one writes:

[6641] if (*p !=0)

[6642] SKIP_SPACES (p, lim);

[6643] else

[6644] . . .

[6645] The presence of two statements—the compound statement and a nullstatement—in between the ‘if’ condition and the ‘else’ makes invalid Ccode.

[6646] The definition of the macro ‘SKIP_SPACES’ can be altered to solvethis problem, using a ‘do . . . while’ statement. Here is how:

[6647] #define SKIP_SPACES (p, limit) \

[6648] do { register char *lim=(limit); \

[6649] while (p !=lim) { \

[6650] if(*p++!=‘ ’) { \

[6651] p−−; break; }}} \

[6652] while (0)

[6653] Now ‘SKIP_SPACES (p, lim);’ expands into

[6654] do {. . . } while (0);

[6655] which is one statement.

[6656] Duplication of Side Effects

[6657] Many C programs define a macro ‘min’, for “minimum”, like this:

[6658] #define min(X, Y) ((X)<(Y) ? (X) : (Y))

[6659] When one uses this macro with an argument containing a sideeffect, as shown here,

[6660] next=min (x+y, foo (z));

[6661] it expands as follows:

[6662] next=((x+y)<(foo (z)) ? (x+y): (foo (z)));

[6663] where ‘x+y’ has been substituted for ‘X’ and ‘foo (z)’ for ‘Y’.The function ‘foo’ is used only once in the statement as it appears inthe program, but the expression ‘foo (z)’ has been substituted twiceinto the macro expansion. As a result, ‘foo’ might be called two timeswhen the statement is executed. If it has side effects or if it takes along time to compute, the results might not be what one intended. ‘min’is declared an unsafe macro. The best solution to this problem is todefine ‘min’ in a way that computes the value of ‘foo (z)’ only once.The C language offers no standard way to do this, but it can be donewith GNU C extensions as follows:

[6664] #define min(X, Y) \

[6665] ({ typeof (X) _x=(X), _y=(Y); \

[6666] (_x<_y) ? _x: _y; })

[6667] If one does not wish to use GNU C extensions, the only solutionis to be careful when using the macro ‘min’. For example, one cancalculate the value of ‘foo (z)’, save it in a variable, and use thatvariable in ‘min’:

[6668] #define min(X, Y) ((X)<(Y) ? (X) : (Y))

[6669] . . .

[6670] {

[6671] int tem=foo (z);

[6672] next=min (x+y, tem);

[6673] }

[6674] (where it is assumed that ‘foo’ returns type ‘int’).

[6675] Self-Referential Macros

[6676] A self-referential macro is one whose name appears in itsdefinition. A special feature of ANSI Standard C is that theself-reference is not considered a macro call. It is passed into thepreprocessor output unchanged.

[6677] Let's consider an example:

[6678] #define foo (4+foo)

[6679] where ‘foo’ is also a variable in the program

[6680] Following the ordinary rules, each reference to ‘foo’ may expandinto ‘(4+foo)’; then this may be rescanned and may expand into‘(4+(4+foo))’; and so on until it causes a fatal error (memory full) inthe preprocessor.

[6681] However, the special rule about self-reference cuts this processshort after one step, at ‘(4+foo)’. Therefore, this macro definition hasthe possibly useful effect of causing the program to add 4 to the valueof ‘foo’ wherever ‘foo’ is referred to. In most cases, it is a bad ideato take advantage of this feature. A person reading the program who seesthat ‘foo’ is a variable may not expect that it is a macro as well. Thereader may come across the identifier ‘foo’ in the program and think itsvalue should be that of the variable ‘foo’, whereas in fact the value isfour greater. The special rule for self-reference applies also toindirect self-reference. This is the case where a macro x expands to usea macro ‘y’, and the expansion of ‘y’ refers to the macro ‘x’. Theresulting reference to ‘x’ comes indirectly from the expansion of ‘x’,so it is a self-reference and is not further expanded. Thus, after

[6682] #define x (4+y)

[6683] #define y (2 * x)

[6684] ‘x’ would expand into ‘(4+(2 * x))’. Clear? But suppose ‘y’ isused elsewhere, not from the definition of ‘x’. Then the use of ‘x’ inthe expansion of ‘y’ is not a self-reference because ‘x’ is not “inprogress”. So it does expand. However, the expansion of ‘x’ contains areference to ‘y’, and that is an indirect self-reference now because ‘y’is “in progress”. The result is that ‘y’ expands to ‘(2 * (4+y))’. It isnot clear that this behavior would ever be useful, but it is specifiedby the ANSI C standard, so one may need to understand it.

[6685] Separate Expansion of Macro Arguments

[6686] It has been explained that the expansion of a macro, includingthe substituted actual arguments, is scanned over again for macro callsto be expanded.

[6687] What really happens is more subtle: first each actual argumenttext is scanned separately for macro calls. Then the results of this aresubstituted into the macro body to produce the macro expansion, and themacro expansion is scanned again for macros to expand. The result isthat the actual arguments are scanned twice to expand macro calls inthem. Most of the time, this has no effect. If the actual argumentcontained any macro calls, they are expanded during the first scan. Theresult therefore contains no macro calls, so the second scan does notchange it. If the actual argument were substituted as given, with noprescan, the single remaining scan would find the same macro calls andproduce the same results. One might expect the double scan to change theresults when a self-referential macro is used in an actual argument ofanother macro: the self-referential macro would be expanded once in thefirst scan, and a second time in the second scan. But this is not whathappens. The self-references that do not expand in the first scan aremarked so that they may not expand in the second scan either.

[6688] The prescan is not done when an argument is stringified orconcatenated. Thus,

[6689] #define str(s) #s

[6690] #define foo 4

[6691] str (foo)

[6692] expands to ‘“foo”’. Once more, prescan has been prevented fromhaving any noticeable effect. More precisely, stringification andconcatenation use the argument as written, in unprescanned form. Thesame actual argument would be used in prescanned form if it issubstituted elsewhere without stringification or concatenation.

[6693] #define str(s) #s lose(s)

[6694] #define foo 4

[6695] str (foo)

[6696] expands to ‘“foo” lose(4)’.

[6697] One might now ask, “Why mention the prescan, if it makes nodifference? And why not skip it and make the preprocessor faster?” Theanswer is that the prescan does make a difference in three specialcases:

[6698] Nested calls to a macro.

[6699] Macros that call other macros that stringify or concatenate.

[6700] Macros whose expansions contain unshielded commas.

[6701] Nested calls to a macro occur when a macro's actual argumentcontains a call to that very macro. For example, if ‘f’ is a macro thatexpects one argument, ‘f (f (1))’ is a nested pair of calls to ‘t’. Thedesired expansion is made by expanding ‘f (1)’ and substituting thatinto the definition of ‘f’. The prescan causes the expected result tohappen. Without the prescan, ‘f (1)’ itself would be substituted as anactual argument, and the inner use of ‘f’ would appear during the mainscan as an indirect self-reference and would not be expanded. Here, theprescan cancels an undesirable side effect (in the medical, notcomputational, sense of the term) of the special rule forself-referential macros. But prescan causes trouble in certain othercases of nested macro calls. Here is an example:

[6702] #define foo a,b

[6703] #define bar(x) lose(x)

[6704] #define lose(x) (1+(x))

[6705] bar(foo)

[6706] It is desired that ‘bar(foo)’ turn into ‘(1+(foo))’, which wouldthen turn into ‘(1+(a,b))’. But instead, ‘bar(foo)’ expands into‘lose(a,b)’, and one get an error because lose requires a singleargument. In this case, the problem is easily solved by the sameparentheses that ought to be used to prevent misnesting of arithmeticoperations:

[6707] #define foo (a,b)

[6708] #define bar(x) lose((x))

[6709] The problem is more serious when the operands of the macro arenot expressions; for example, when they are statements. Then parenthesesare unacceptable because they would make for invalid C code:

[6710] #define foo { int a, b; . . . }.

[6711] In GNU C one can shield the commas using the ‘({. . . })’construct which turns a compound statement into an expression:

[6712] #define foo ({ int a, b; . . . })

[6713] Or one can rewrite the macro definition to avoid such commas:

[6714] #define foo { int a; int b; . . . }

[6715] There is also one case where prescan is useful. It is possible touse prescan to expand an argument and then stringify it—if one uses twolevels of macros. Let's add a new macro ‘xstr’ to the example shownabove:

[6716] #define xstr(s) str(s)

[6717] #define str(s) #s

[6718] #define foo 4

[6719] xstr (foo)

[6720] This expands into ‘“4”’, not ‘“foo”’. The reason for thedifference is that the argument of ‘xstr’ is expanded at prescan(because ‘xstr’ does not specify stringification or concatenation of theargument). The result of prescan then forms the actual argument for‘str’. ‘str’ uses its argument without prescan because it performsstringification; but it cannot prevent or undo the prescanning alreadydone by ‘xstr’.

[6721] Cascaded Use of Macros

[6722] A cascade of macros is when one macro's body contains a referenceto another macro. This is very common practice. For example,

[6723] #define BUFSIZE 1020

[6724] #define TABLESIZE BUFSIZE.

[6725] This is not at all the same as defining ‘TABLESIZE’ to be ‘1020’.The ‘#define’ for ‘TABLESIZE’ uses exactly the body one specifies—inthis case, ‘BUFSIZE’—and does not check to see whether it too is thename of a macro.

[6726] It's only when one uses ‘TABLESIZE’ that the result of itsexpansion is checked for more macro names. This makes a difference ifone changes the definition of ‘BUFSIZE’ at some point in the sourcefile. ‘TABLESIZE’, defined as shown, may always expand using thedefinition of ‘BUFSIZE’ that is currently in effect:

[6727] #define BUFSIZE 1020

[6728] #define TABLESIZE BUFSIZE

[6729] #undef BUFSIZE

[6730] #define BUFSIZE 37

[6731] Now ‘TABLESIZE’ expands (in two stages) to ‘37’. (The ‘#undef’ isto prevent any warning about the nontrivial redefinition of BUFSIZE.)

[6732] Newlines in Macro Arguments

[6733] Traditional macro processing carries forward all newlines inmacro arguments into the expansion of the macro. This means that, ifsome of the arguments are substituted more than once, or not at all, orout of order, newlines can be duplicated, lost, or moved around withinthe expansion. If the expansion consists of multiple statements, thenthe effect is to distort the line numbers of some of these statements.The result can be incorrect line numbers, in error messages or displayedin a debugger. The GNU C preprocessor operating in ANSI C mode adjustsappropriately for multiple use of an argument—the first use expands allthe newlines, and subsequent uses of the same argument produce nonewlines. But even in this mode, it can produce incorrect line numberingif arguments are used out of order, or not used at all.

[6734] Here is an example illustrating this problem:

[6735] #define ignore_second_arg(a,b,c) a; c

[6736] ignore_second_arg (foo ( ),

[6737] ignored ( ),

[6738] syntax error);

[6739] The syntax error triggered by the tokens ‘syntax error’ resultsin an error message citing line four, even though the statement textcomes from line five.

Conditionals

[6740] Introduction

[6741] In a macro processor, a conditional is a directive that allows apart of the program to be ignored during compilation, on someconditions. In the C preprocessor, a conditional can test either anarithmetic expression or whether a name is defined as a macro. Aconditional in the C preprocessor resembles in some ways an ‘if’statement in C, but it is important to understand the difference betweenthem. The condition in an ‘if’ statement is tested during the executionof the program. Its purpose is to allow the program to behavedifferently from run to run, depending on the data it is operating on.The condition in a preprocessing conditional directive is tested whenthe program is compiled. Its purpose is to allow different code to beincluded in the program depending on the situation at the time ofcompilation.

[6742] Why Conditionals are Used

[6743] Generally there are three kinds of reason to use a conditional.

[6744] A program may need to use different code depending on the machineor operating system it is to run on. In some cases the code for oneoperating system may be erroneous on another operating system; forexample, it might refer to library routines that do not exist on theother system. When this happens, it is not enough to avoid executing theinvalid code: merely having it in the program makes it impossible tolink the program and run it.

[6745] With a preprocessing conditional, the offending code can beeffectively excised from the program when it is not valid.

[6746] One may want to be able to compile the same source file into twodifferent programs.

[6747] Sometimes the difference between the programs is that one makesfrequent time-consuming consistency checks on its intermediate data, orprints the values of those data for debugging, while the other does not.

[6748] A conditional whose condition is always false is a good way toexclude code from the program but keep it as a sort of comment forfuture reference.

[6749] Most simple programs that are intended to run on only one machinemay not need to use preprocessing conditionals.

[6750] Syntax of Conditionals

[6751] A conditional in the C preprocessor begins with a conditionaldirective: ‘#if’, ‘#ifdef’ or ‘#ifndef’. More information on '#ifdef’and '#ifndef’ will be set forth hereinafter with only ‘#if’ is explainedhere.

[6752] The ‘#if’ Directive

[6753] The ‘#if’ directive in its simplest form consists of

[6754] #if expression

[6755] controlled text

[6756] #endif /* expression */

[6757] The comment following the ‘#endif’ is not required, but it is agood practice because it helps people match the ‘#endif’ to thecorresponding ‘#if’. Such comments should always be used, except inshort conditionals that are not nested. In fact, one can put anything atall after the ‘#endif’ and it may be ignored by the GNU C preprocessor,but only comments are acceptable in ANSI Standard C.

[6758] expression is a C expression of integer type, subject tostringent restrictions. It may contain:

[6759] Integer constants, which are all regarded as long or unsignedlong.

[6760] Character constants, which are interpreted according to thecharacter set and conventions of the machine and operating system onwhich the preprocessor is running. The GNU C preprocessor uses the Cdata type ‘char’ for these character constants; therefore, whether somecharacter codes are negative is determined by the C compiler used tocompile the preprocessor. If it treats ‘char’ as signed, then charactercodes large enough to set the sign bit may be considered negative;otherwise, no character code is considered negative.

[6761] Arithmetic operators for addition, subtraction, multiplication,division, bitwise operations, shifts, comparisons, and logicaloperations (‘&&’ and ‘∥’).

[6762] Identifiers that are not macros, which are all treated aszero(!). Macro calls. All macro calls in the expression are expandedbefore actual computation of the expression's value begins. Note that‘sizeof’ operators and enum-type values are not allowed. enum-typevalues, like all other identifiers that are not taken as macro calls andexpanded, are treated as zero.

[6763] The controlled text inside of a conditional can includepreprocessing directives. Then the directives inside the conditional areobeyed only if that branch of the conditional succeeds. The text canalso contain other conditional groups. However, the ‘#if’ and ‘#endif’directives may balance.

[6764] The ‘#else’ Directive

[6765] The ‘#else’ directive can be added to a conditional to providealternative text to be used if the condition is false. This is what itlooks like:

[6766] #if expression

[6767] text-if-true

[6768] #else /* Not expression */

[6769] text-if-false

[6770] #endif /* Not expression */

[6771] If expression is nonzero, and thus the text-if-true is active,then ‘#else’ acts like a failing conditional and the text-if-false isignored. Contrariwise, if the ‘#if’ conditional fails, the text-if-falseis considered included.

[6772] The ‘#elif’ Directive

[6773] One common case of nested conditionals is used to check for morethan two possible alternatives. For example, one might have

[6774] #if==X 1

[6775] . . .

[6776] #else /* X !=1 */

[6777] #if X==2

[6778] . . .

[6779] #else /*X !=2 */

[6780] . . .

[6781] #endif /* X !=2 */

[6782] #endif /* X !=1 */

[6783] Another conditional directive, ‘#elif’, allows this to beabbreviated as follows:

[6784] #if X==1

[6785] . . .

[6786] #elif X==2

[6787] . . .

[6788] #else /* X !=2 and X

[6789] #endif /* X !=2 and X !=1*/

[6790] ‘#elif’ stands for “else if”. Like ‘#else’, it goes in the middleof a ‘#if’-‘#endif’ pair and subdivides it; it does not require amatching ‘#endif’ of its own. Like ‘#if’, the ‘#elif’ directive includesan expression to be tested.

[6791] The text following the ‘#elif’ is processed only if the original‘#if’-condition failed and the ‘#elif’ condition succeeds. More than one‘#elif’ can go in the same ‘#if’-‘#endif’ group. Then the text aftereach ‘#elif’ is processed only if the ‘#elif’ condition succeeds afterthe original ‘#if’ and any previous ‘#elif’ directives within it havefailed. ‘#else’ is equivalent to ‘#elif 1’, and ‘#else’ is allowed afterany number of ‘#elif’ directives, but ‘#elif’ may not follow ‘#else’.

[6792] Keeping Deleted Code for Future Reference

[6793] If one replaces or deletes a part of the program but want to keepthe old code around as a comment for future reference, the easy way todo this is to put ‘#if 0’ before it and ‘#endif’ after it. This isbetter than using comment delimiters ‘/*’ and ‘*/’ since those won'twork if the code already contains comments (C comments do not nest).This works even if the code being turned off contains conditionals, butthey may be entire conditionals (balanced ‘#if’ and ‘#endif’).

[6794] Conversely, do not use ‘#if 0’ for comments which are not C code.Use the comment delimiters ‘/*’ and ‘*/’ instead. The interior of ‘#if0’ may consist of complete tokens; in particular, single quotecharacters may balance. But comments often contain unbalanced singlequote characters (known in English as apostrophes). These confuse ‘#if0’. They do not confuse ‘/*’.

[6795] Conditionals and Macros

[6796] Conditionals are useful in connection with macros or assertions,because those are the only ways that an expression's value can vary fromone compilation to another. A ‘#if’ directive whose expression uses nomacros or assertions is equivalent to ‘#if 1’ or ‘#if 0’; one might aswell determine which one, by computing the value of the expression, andthen simplify the program. For example, here is a conditional that teststhe expression:

[6797] ‘BUFSIZE==1020’, where ‘BUFSIZE’ may be a macro.

[6798] #if BUFSIZE==1020

[6799] printf (“Large buffers!\n”);

[6800] #endif/* BUFSIZE is large */

[6801] (Programmers often wish they could test the size of a variable ordata type in ‘#if’, but this does not work. The preprocessor does notunderstand sizeof, or typedef names, or even the type keywords such asint.)

[6802] The special operator ‘defined’ is used in ‘#if’ expressions totest whether a certain name is defined as a macro. Either ‘defined name’or ‘defined (name)’ is an expression whose value is 1 if name is definedas macro at the current point in the program, and 0 otherwise. For the‘defined’ operator it makes no difference what the definition of themacro is; all that matters is whether there is a definition. Thus, forexample,

[6803] #if defined (vax) ∥ defined (ns 16000)

[6804] would succeed if either of the names ‘vax’ and ‘ns16000’ isdefined as a macro. One can test the same condition using assertion,like this:

[6805] #if #cpu (vax) ∥ #cpu (ns16000)

[6806] If a macro is defined and later undefined with ‘#undef’,subsequent use of the ‘defined’ operator returns 0, because the name isno longer defined. If the macro is defined again with another

[6807] ‘#define’,

[6808] ‘defined’ may recommence returning 1.

[6809] Conditionals that test whether just one name is defined are verycommon, so there are two special short conditional directives for thiscase.

[6810] #ifdef name is equivalent to ‘#if defined ( name)’.

[6811] #ifndef name is equivalent to ‘#if ! defined ( name)’.

[6812] Macro definitions can vary between compilations for severalreasons.

[6813] Some macros are predefined on each kind of machine. For example,on a Vax, the name ‘vax’ is a predefined macro. On other machines, itwould not be defined.

[6814] Many more macros are defined by system header files. Differentsystems and machines define different macros, or give them differentvalues. It is useful to test these macros with conditionals to avoidusing a system feature on a machine where it is not implemented.

[6815] Macros are a common way of allowing users to customize a programfor different machines or applications. For example, the macro ‘BUFSIZE’might be defined in a configuration file for the program that isincluded as a header file in each source file. One would use ‘BUFSIZE’in a preprocessing conditional in order to generate different codedepending on the chosen configuration.

[6816] Macros can be defined or undefined with ‘-D’ and ‘-U’ commandoptions when one compiles the program. One can arrange to compile thesame source file into two different programs by choosing a macro name tospecify which program one want, writing conditionals to test whether orhow this macro is defined and then controlling the state of the macrowith compiler command options.

[6817] Assertions

[6818] Assertions are a more systematic alternative to macros in writingconditionals to test what sort of computer or system the compiledprogram may run on. Assertions are usually predefined, but one candefine them with preprocessing directives or command-line options. Themacros traditionally used to describe the type of target are notclassified in any way according to which question they answer; they mayindicate a hardware architecture, a particular hardware model, anoperating system, a particular version of an operating system, orspecific configuration options. These are jumbled together in a singlenamespace. In contrast, each assertion consists of a named question andan answer. The question is usually called the predicate. An assertionlooks like this:

[6819] # predicate ( answer)

[6820] One may use a properly formed identifier for predicate. The valueof answer can be any sequence of words; all characters are significantexcept for leading and trailing whitespace, and differences in internalwhitespace sequences are ignored. Thus, ‘x+y’ is different from ‘x+y’but equivalent to ‘x+y’. ‘)’ is not allowed in an answer.

[6821] Here is a conditional to test whether the answer is asserted forthe predicate:

[6822] #if # predicate (answer) There may be more than one answerasserted for a given predicate. If one omit the answer, one can testwhether any answer is asserted for predicate: #if # predicate

[6823] Most of the time, the assertions one test may be predefinedassertions. GNU C provides three predefined predicates: system, cpu, andmachine. system is for assertions about the type of software, cpudescribes the type of computer architecture, and machine gives moreinformation about the computer. For example, on a GNU system, thefollowing assertions would be true:

[6824] #system (gnu)

[6825] #system (mach)

[6826] #system (mach 3)

[6827] #system (mach 3. subversion)

[6828] #system (hurd)

[6829] #system (hurd version) and perhaps others. The alternatives withmore or less version information let one ask more or less detailedquestions about the type of system software. On a Unix system, one wouldfind #system (unix) and perhaps one of: #system (aix), #system (bsd),#system (hpux), #system (lynx), #system (mach), #system (posix), #system(svr3), #system (svr4), or #system (xpg4) with possible version numbersfollowing.

[6830] Other values for system are #system (mvs) and #system (vms).Portability note: Many Unix C compilers provide only one answer for thesystem assertion: #system (unix), if they support assertions at all.This is less than useful. An assertion with a multi-word answer iscompletely different from several assertions with individual single-wordanswers. For example, the presence of system (mach 3.0) does not meanthat system (3.0) is true. It also does not directly imply system(mach), but in GNU C, that last may normally be asserted as well.

[6831] The current list of possible assertion values for cpu is:

[6832] #cpu

[6833] (a29k), #cpu (alpha), #cpu (arm), #cpu (clipper), #cpu

[6834] (convex), #cpu (elxsi), #cpu (tron), #cpu (h8300), #cpu

[6835] (i370), #cpu (i386), #cpu (i860), #cpu (i960), #cpu (m68k),

[6836] #cpu (m88k), #cpu (mips), #cpu (ns32k), #cpu (hppa), #cpu

[6837] (pyr), #cpu (ibm032), #cpu (rs6000), #cpu (sh), #cpu.

[6838] (sparc), #cpu (spur), #cpu (tahoe), #cpu (vax), #cpu

[6839] (we32000).

[6840] One can create assertions within a C program using ‘#assert’,like this:

[6841] #assert predicate ( answer)

[6842] (Note the absence of a ‘#’ before predicate.)

[6843] Each time one does this, one asserts a new true answer forpredicate. Asserting one answer does not invalidate previously assertedanswers; they all remain true. The only way to remove an assertion iswith ‘#unassert’. ‘#unassert’ has the same syntax as ‘#assert’. One canalso remove all assertions about predicate like this: #unassertpredicate. One can also add or cancel assertions using command optionswhen he or she runs gcc or cpp.

[6844] The ‘#error’ and ‘#warning’ Directives

[6845] The directive ‘#error’ causes the preprocessor to report a fatalerror. The rest of the line that follows ‘#error’ is used as the errormessage.

[6846] One would use ‘#error’ inside of a conditional that detects acombination of parameters which he or she knows the program does notproperly support. For example, if one knows that the program may not runproperly on a Vax, one might write

[6847] #ifdef_vax_(—)

[6848] #error Won't work on Vaxen. See comments at

[6849] get last object.

[6850] #endif

[6851] If one has several configuration parameters that may be set up bythe installation in a consistent way, he or she can use conditionals todetect an inconsistency and report it with ‘#error’. For example,

[6852] #if HASH_TABLE_SIZE % 2==0 ∥ HASH_TABLE_SIZE % 3==0 \

[6853] ∥ HASH_TABLE_SIZE % 5==0

[6854] #error HASH_TABLE_SIZE should not be divisible by a small \

[6855] prime

[6856] #endif

[6857] The directive ‘#warning’ is like the directive ‘#error’, butcauses the preprocessor to issue a warning and continue preprocessing.The rest of the line that follows ‘#warning’ is used as the warningmessage.

[6858] One might use ‘#warning’ in obsolete header files, with a messagedirecting the user to the header file which should be used instead.

Additional Preprocessor Information

[6859] Combining Source Files

[6860] One of the jobs of the C preprocessor is to inform the C compilerof where each line of C code came from: which source file and which linenumber.

[6861] C code can come from multiple source files if one use‘#include’;both ‘#include’ and the use of conditionals and macros cancause the line number of a line in the preprocessor output to bedifferent from the line's number in the original source file. One mayappreciate the value of making both the C compiler (in error messages)and symbolic debuggers such as GDB use the line numbers in the sourcefile.

[6862] The C preprocessor builds on this feature by offering a directiveby which one can control the feature explicitly. This is useful when afile for input to the C preprocessor is the output from another programsuch as the bison parser generator, which operates on another file thatis the true source file. Parts of the output from bison are generatedfrom scratch, other parts come from a standard parser file. The rest arecopied nearly verbatim from the source file, but their line numbers inthe bison output are not the same as their original line numbers.Naturally one would like compiler error messages and symbolic debuggersto know the original source file and line number of each line in thebison input.

[6863] bison arranges this by writing ‘#line’ directives into the outputfile. ‘#line’ is a directive that specifies the original line number andsource file name for subsequent input in the current preprocessor inputfile ‘#line’ has three variants:

[6864] #line linenum

[6865] Here linenum is a decimal integer constant. This specifies thatthe line number of the following line of input, in its original sourcefile, was linenum.

[6866] #line linenum filename

[6867] Here linenum is a decimal integer constant and filename is astring constant. This specifies that the following line of input cameoriginally from source file filename and its line number there waslinenum. Keep in mind that filename is not just a file name; it issurrounded by doublequote characters so that it looks like a stringconstant.

[6868] #line anything else

[6869] anything else is checked for macro calls, which are expanded. Theresult should be a decimal integer constant followed optionally by astring constant, as described above.

[6870] ‘#line’ directives alter the results of the ‘_FILE_’ and‘_LINE_(’ predefined macros from that point on.)

[6871] The output of the preprocessor (which is the input for the restof the compiler) contains directives that look much like ‘#line’directives. They start with just ‘#’ instead of ‘#line’, but this isfollowed by a line number and file name as in ‘#line’.

[6872] Miscellaneous Preprocessing Directives

[6873] This section describes three additional preprocessing directives.They are not very useful, but are mentioned for completeness. The nulldirective consists of a ‘#’ followed by a Newline, with only whitespace(including comments) in between. A null directive is understood as apreprocessing directive but has no effect on the preprocessor output.The primary significance of the existence of the null directive is thatan input line consisting of just a ‘#’ may produce no output, ratherthan a line of output containing just a ‘#’. Supposedly some old Cprograms contain such lines.

[6874] The ANSI standard specifies that the ‘#pragma’ directive has anarbitrary, implementation defined effect. In the GNU C preprocessor,‘#pragma’ directives are not used, except for ‘#pragma once’. However,they are left in the preprocessor output, so they are available to thecompilation pass. The ‘#ident’ directive is supported for compatibilitywith certain other systems. It is followed by a line of text. On somesystems, the text is copied into a special place in the object file; onmost systems, the text is ignored and this directive has no effect.Typically ‘#ident’ is only used in header files supplied with thosesystems where it is meaningful.

[6875] C Preprocessor Output

[6876] The output from the C preprocessor looks much like the input,except that all preprocessing directive lines have been replaced withblank lines and all comments with spaces. Whitespace within a line isnot altered; however, a space is inserted after the expansions of mostmacro calls.

[6877] Source file name and line number information is conveyed by linesof the form

[6878] # linenum filename flags

[6879] which are inserted as needed into the middle of the input (butnever within a string or character constant). Such a line means that thefollowing line originated in file filename at line linenum.

[6880] After the file name comes zero or more flags, which are ‘1’, ‘2’,‘3’, or ‘4’. If there are multiple flags, spaces separate them. Here iswhat the flags mean:

[6881] ‘1’ This indicates the start of a new file.

[6882] ‘2’ This indicates returning to a file (after having includedanother file).

[6883] ‘3’ This indicates that the following text comes from a systemheader file, so certain warnings should be suppressed.

[6884] ‘4’ This indicates that the following text should be treated asC.

[6885] Invoking the C Preprocessor

[6886] Introduction

[6887] Most often when one uses the C preprocessor he or she may nothave to invoke it explicitly: the C compiler may do so automatically.However, the preprocessor is sometimes useful on its own. The Cpreprocessor expects two file names as arguments, infile and outfile.The preprocessor reads infile together with any other files it specifieswith ‘#include’. All the output generated by the combined input files iswritten in outfile. Either infile or outfile may be ‘-’, which as infilemeans to read from standard input and as outfile means to write tostandard output. Also, if outfile or both file names are omitted, thestandard output and standard input are used for the omitted file names.

[6888] Command Line Options

[6889] Here is a table of command options accepted by the Cpreprocessor. These options can also be given when compiling a Cprogram; they are passed along automatically to the preprocessor when itis invoked by the compiler.

[6890] ‘-P’

[6891] Inhibit generation of ‘#’-lines with line-number information inthe output from the preprocessor. This might be useful when running thepreprocessor on something that is not C code and may be sent to aprogram which might be confused by the ‘#’-lines.

[6892] ‘-C’

[6893] Do not discard comments: pass them through to the output file.Comments appearing in arguments of a macro call may be copied to theoutput before the expansion of the macro call.

[6894] ‘traditional’

[6895] Try to imitate the behavior of old-fashioned C, as opposed toANSI C. Traditional macro expansion pays no attention to singlequote ordoublequote characters; macro argument symbols are replaced by theargument values even when they appear within apparent string orcharacter constants.

[6896] Traditionally, it is permissible for a macro expansion to end inthe middle of a string or character constant. The constant continuesinto the text surrounding the macro call.

[6897] However, traditionally the end of the line terminates a string orcharacter constant, with no error.

[6898] In traditional C, a comment is equivalent to no text at all. (InANSI C, a comment counts as whitespace.)

[6899] Traditional C does not have the concept of a “preprocessingnumber”. It considers ‘1.0e+4’ to be three tokens: ‘1.0e’, ‘+’, and ‘4’.

[6900] A macro is not suppressed within its own definition, intraditional C. Thus, any macro that is used recursively inevitablycauses an error.

[6901] The character ‘#’ has no special meaning within a macrodefinition in traditional C.

[6902] In traditional C, the text at the end of a macro expansion canrun together with the text after the macro call, to produce a singletoken. (This is impossible in ANSI C.)

[6903] Traditionally, ‘\’ inside a macro argument suppresses thesyntactic significance of the following character.

[6904] ‘-trigraphs’

[6905] Process ANSI standard trigraph sequences. These arethree-character sequences, all starting with ‘??’, that are defined byANSI C to stand for single characters. For example, ‘??/’ stands for‘\’, so “??/n” is a character constant for a newline. Strictly speaking,the GNU C preprocessor does not support all programs in ANSI Standard Cunless ‘-trigraphs’ is used, but if one ever notices the difference itmay be with relief.

[6906] One doesn't want to know any more about trigraphs.

[6907] ‘-pedantic’

[6908] Issue warnings required by the ANSI C standard in certain casessuch as when text other than a comment follows ‘#else’ or ‘#endif’.

[6909] ‘-pedantic-errors’

[6910] Like ‘-pedantic’, except that errors are produced rather thanwarnings.

[6911] ‘-Wtrigraphs’

[6912] Warn if any trigraphs are encountered (assuming they areenabled).

[6913] ‘-Wcomment’

[6914] Warn whenever a comment-start sequence ‘/*’ appears in a comment.‘-Wall’

[6915] Requests both ‘-Wtrigraphs’ and ‘-Wcomment’ (but not‘-Wtraditional’).

[6916] ‘-Wtraditional’

[6917] Warn about certain constructs that behave differently intraditional and ANSI C.

[6918] ‘-I directory’

[6919] Add the directory to the head of the list of directories to besearched for header file. This can be used to override a system headerfile, substituting the version, since these directories are searchedbefore the system header file directories. If one uses more than one‘-I’ option, the directories are scanned in left-to-right order; thestandard system directories come after.

[6920] ‘-I-’

[6921] Any directories specified with ‘-I’ options before the ‘-I-’option are searched only for the case of ‘#include “file”’; they are notsearched for ‘#include <file>’. If additional directories are specifiedwith ‘-I’ options after the ‘-I-’, these directories are searched forall ‘#include’ directives. In addition, the ‘-I-’ option inhibits theuse of the current directory as the first search directory for ‘#include“file”’. Therefore, the current directory is searched only if it isrequested explicitly with ‘-I.’ Specifying both ‘-I-’ and ‘-I.’ allowsone to control precisely which directories are searched before thecurrent one and which are searched after.

[6922] ‘-nostdinc’

[6923] Do not search the standard system directories for header files.Only the directories one have specified with ‘-I’ options (and thecurrent directory, if appropriate) are searched.

[6924] ‘-nostdinc++’

[6925] Do not search for header files in the C++-specific standarddirectories, but do still search the other standard directories. (Thisoption is used when building libg++.)

[6926] ‘-D name’

[6927] Predefine name as a macro, with definition ‘I’. ‘-Dname=definition’

[6928] Predefine name as a macro, with definition. There are norestrictions on the contents of definition, but if one is invoking thepreprocessor from a shell or shell-like program one may need to use theshell's quoting syntax to protect characters such as spaces that have ameaning in the shell syntax. If one uses more than one ‘-D’ for the samename, the rightmost definition takes effect.

[6929] ‘-U name’

[6930] Do not predefine name. If both ‘-U’ and ‘-D’ are specified forone name, the ‘-U’ beats the ‘-D’ and the name is not predefined.

[6931] ‘-under’

[6932] Do not predefine any nonstandard macros.

[6933] ‘-A predicate( answer)’

[6934] Make an assertion with the predicate and answer.

[6935] One can use ‘-A-’ to disable all predefined assertions; it alsoundefines all predefined macros that identify the type of target system.

[6936] ‘-dM’

[6937] Instead of outputting the result of preprocessing, output a listof ‘#define’ directives for all the macros defined during the executionof the preprocessor, including predefined macros. This gives one a wayof finding out what is predefined in the version of the preprocessor;assuming one have no file ‘foo.h’, the command

[6938] touch foo.h; cpp -dM foo.h

[6939] may show the values of any predefined macros.

[6940] ‘-dD’

[6941] Like ‘-dM’ except in two respects: it does not include thepredefined macros, and it outputs both the ‘#define’ directives and theresult of preprocessing. Both kinds of output go to the standard outputfile.

[6942] ‘-M [-MG]’

[6943] Instead of outputting the result of preprocessing, output a rulesuitable for make describing the dependencies of the main source file.The preprocessor outputs one make rule containing the object file namefor that source file, a colon, and the names of all the included files.If there are many included files then the rule is split into severallines using

[6944] ‘\’-newline.

[6945] ‘-MG’ says to treat missing header files as generated files andassume they live in the same directory as the source file. It may bespecified in addition to ‘-M’.

[6946] This feature is used in automatic updating of makefiles.

[6947] ‘-MM [-MG]’

[6948] Like ‘-M’ but mention only the files included with ‘#include“file”’. System header files included with ‘#include <file>’ areomitted.

[6949] ‘-MD file’

[6950] Like ‘-M’ but the dependency information is written to file. Thisis in addition to compiling the file as specified -‘-MD’ does notinhibit ordinary compilation the way ‘-M’ does. When invoking gcc, donot specify the file argument. Gcc may create file names made byreplacing “.c” with “.d” at the end of the input file names. In Mach,one can use the utility md to merge multiple dependency files into asingle dependency file suitable for using with the ‘make’ command.

[6951] ‘-MMD file’

[6952] Like ‘-MD’ except mention only user header files, not systemheader files.

[6953] ‘-H’

[6954] Print the name of each header file used, in addition to othernormal activities.

[6955] ‘-imacros file’

[6956] Process file as input, discarding the resulting output, beforeprocessing the regular input file. Because the output generated fromfile is discarded, the only effect of ‘-imacros file’ is to make themacros defined in file available for use in the main input.

[6957] ‘-include file’

[6958] Process file as input, and include all the resulting output,before processing the regular input file.

[6959] ‘-idirafter dir’

[6960] Add the directory dir to the second include path. The directorieson the second include path are searched when a header file is not foundin any of the directories in the main include path (the one that ‘-I’adds to).

[6961] ‘-iprefix prefix’

[6962] Specify prefix as the prefix for subsequent ‘-iwithprefix’options.

[6963] ‘-iwithprefix dir’

[6964] Add a directory to the second include path. The directory's nameis made by concatenating prefix and dir, where prefix was specifiedpreviously with ‘-iprefix’.

[6965] ‘-isystem dir’

[6966] Add a directory to the beginning of the second include path,marking it as a system directory, so that it gets the same specialtreatment as is applied to the standard system directories.

[6967] ‘-lang-c’

[6968] ‘-lang-c89’

[6969] ‘-lang-c++’

[6970] ‘-lang-objc’

[6971] ‘-lang-objc++’

[6972] Specify the source language. ‘-lang-c’ is the default; it allowsrecognition of C++ comments (comments that begin with ‘//’ and end atend of line), since this is a common feature and it may most likely bein the next C standard. ‘-lang-c89’ disables recognition of C++ comments‘-lang-c++’ handles C++ comment syntax and includes extra defaultinclude directories for C++. ‘-lang-objc’ enables the Objective C‘#import’ directive. ‘-lang-objc++’ enables both C++ and Objective Cextensions. These options are generated by the compiler driver gcc, butnot passed from the ‘gcc’ command line unless one use the driver's ‘-Wp’option.

[6973] ‘-lint’

[6974] Look for commands to the program checker lint embedded incomments, and emit them preceded by ‘#pragma lint’.

[6975] For example, the comment ‘/* NOTREACHED */’ becomes ‘#pragma lintNOTREACHED’. This option is available only when one call cpp directly;gcc may not pass it from its command line.

[6976] ‘-$’

[6977] Forbid the use of ‘$’ in identifiers. This is required for ANSIconformance. gcc automatically supplies this option to the preprocessorif one specify ‘-ansi’, but gcc doesn't recognize the ‘-$’ optionitself-to use it without the other effects of ‘-ansi’, one may call thepreprocessor directly.

FPGA-based Co-processor API

[6978] The present section specifies in detail the performance andfunctional specification of one embodiment of the present invention. Thepresent section describes how the various requirements are to be met. Italso documents all the tests necessary to verify that each Handel-Cand/or software unit functions correctly and that they integrate to workas one complete application.

[6979] In the context of the present section, various embodiments willnow be set forth, and further elaborated upon subsequently duringreference to FIGS. 88 through 92. It should be noted that the presentembodiments are also particularly pertinent to the earlier discussionsof parameterized macros under the heading “Parameterized macroexpressions” set forth hereinabove during reference to FIG. 57A-2 andsubsequent figures.

[6980]FIG. 87B illustrates a method 8750 for distributing cores, inaccordance with one embodiment of the present invention. In general, inoperation 8752, a core that includes a plurality of first variables isdistributed without reference to at one or more parameters. In oneaspect of the present invention, the core may be distributed over anetwork. As an option, the network may include the Internet.

[6981] In one embodiment, the one or more parameters may includevariable width. In further aspect, the one or more parameters mayinclude data type. In even another aspect, the one or more parametersmay include array size. In another aspect, the one or more parametersmay include pipeline depth.

[6982] A computer program is then executed that includes a plurality ofsecond variables with reference to the one or more parameter. Seeoperation 8754. The execution of the computer program includes executionof the core. The one or more parameters of the first variables are theninferred from the one or more parameters of the second variables. Seeoperation 8756.

[6983] By this design, the various principles disclosed herein may beused in a distributed environment where cores may be disseminatedutilizing a network, and used by various computer applications.

[6984]FIG. 87C illustrates a method 8760 for using a library map duringthe design of cores, in accordance with one embodiment of the presentinvention. In general, in operation 8762, a plurality of macros whichspecify an interface is determined. In one aspect, the macros may becompiled in a file.

[6985] During the execution of each of macro, one of a plurality oflibraries is utilized in operation 8764. Each macro is capable of beingexecuted utilizing different libraries. Note operation 8766. As anoption, the macros may be executed on a co-processor which is capable ofexecuting the macros utilizing different libraries.

[6986] In one embodiment of the present invention, a plurality of firstvariables in the macros may also be defined with reference to variablewidths, and a plurality of second variables in the macros may be definedwithout reference to variable widths so that the variable widths of thesecond variables may be inferred from the variable widths of the firstvariables.

[6987] The present invention is thus adapted for automaticallygenerating libraries for use in distributing software components withoutrequiring the software components to be completely defined. The systemreceives a behavioral description of the system components anddetermines the optimal required functionality between hardware andsoftware and provides that functionality while varying the parameters(e.g. size or power) of the hardware and/or software. Thus, forinstance, the hardware and the processors for the software can be formedon a reconfigurable logic device, each being no bigger than is necessaryto form the desired functions. The codesign system outputs a descriptionof the required processors, machine code to run on the processors, and anet list or register transfer level description of the necessaryhardware. It is possible for the user to write some parts of thedescription of the system at register transfer level to give closercontrol over the operation of the system, and the user can specify theprocessor or processors to be used, and can change, for instance, thepartitioner, compilers or speed estimators used in the codesign system.Since the library has the latest technology in dynamic widths, thelibraries are flexible in their ability to store and dynamically updatetheir components based on the characteristics of a resolved system.

[6988] In another aspect of the present invention, a set of macros isinitially developed to specify an interface. The hardware interface isthus specified using software macros. For example, a macro that says addA+B=C may translate into an adder with two input ports and an output.

[6989] As an option, a Handel-C file and a header file may beimplemented with the declarations for the macros or file.

[6990] Thereafter, the C file may be compiled into a library. Thevariables may not be fully resolved at this point. The Handel C compilermay do width inferencing when the library is utilized in a program call.A width of constant values or a whole expression may inferred. Externalreferences may also be made to another macro that may not be in thatparticular library that was resolved to the other library when the callwas invoked. Function pointers can also encapsulate a whole piece ofhardware which can be resolved at runtime.

[6991] For example, in a system with two memory banks connected togetherin a FPGA, a pointer may point to a function pointer. Then, suchfunction pointer can be assigned to any function and have several (i.e.seven (7)) functions that can be pointed to by the function pointer.Then, at runtime it could be resolved using the Handel-C RAM function topoint to different memory banks to implement a multiplexor to any of thememory banks.

[6992] In another embodiment, three different graphic adapters could bedefined by three different functions that were pointed to by a singlefunction pointer. Such single function pointer could be changed atruntime to point to particular circuitry of the particular adapter thatis to be executed. Also, the functionality of the device may beencapsulated in the API structure to switch between various video cards.

[6993] One example of such concept will be set forth hereinafter underthe heading “Application Layer User Function Interface.” Such exampleutilizes a FPGA co-processor to pass the structure USER API Structurecontaining function pointers.

[6994] In use, when a programmer writes an expression once, he or shedoes not need to recode it every time. A macro is provided that compilesinto a function that does something, but the programmer does not knowwhat it does. One does not need the declarations for this call. Two verydifferent functions are processed: version 1 or version 2; based onwhich one is enabled. This method is thus very configurable.

[6995] An arithmetic logic unit is defined that has a binary library anda floating point library. Then, in a co-processor system, one couldpoint to one or the other of the platforms. The design of two differentIP cores may be skipped, since two different versions of the IP Coresmay be produced for the two different libraries. The functions may beused to make calls to the various points of the hardware from thepointers in the header file.

[6996] All of this may be done in the context of a co-processor system.As shown in FIG. 90, an Application Layer library and a Physical Layerlibrary are provided. For each platform for which there is memory, onewould have a separate library that defines the particular platform andits unique memory handling techniques. Header files that accompany thelibraries may be called by User Core Implementation to access the memoryof the physical core. It should be noted that the physical layer is setforth hereinafter in greater detail in the section under the heading“Physical Layer Interface.”

[6997]FIG. 87D illustrates a method 8770 for providing polymorphismusing pointers, in accordance with one embodiment of the presentinvention. Operations are initially performed on a plurality of objectsin multiple contexts using operators, as indicated in operation 8772. Inone aspect, the operations may include video operations.

[6998] In accordance with the concept of polymorphism, differentmeanings are assigned to the operators in each of the contexts. Noteoperation 8774. To enhance such concept, the meanings are assigned tothe operators in each of the contexts using pointers. Note operation8776. In one aspect, the meanings may include functions. As an optoin,the meanings may be assigned during run-time. Further, the meanings maybe selected utilizing a multiplexer.

[6999] The present embodiment allows mapping of video cards that caneach be defined by a separate function. A single function pointer can bechanged at runtime to point to any of the various functions. In oneembodiment, a multiplexor switch may be used that points to one of anumber of the function pointers.

[7000]FIG. 87E illustrates a method 8780 for generating librariesutilizing pre-compiler macros, in accordance with one embodiment of thepresent invention. In general, in operation 8782, a library is accessedthat includes a plurality of functions. A precompiler constant is testedin operation 8784 so that one or more of the functions of the librarycan be selected based on the testing. Note operation 8786.

[7001] In one aspect, the precompiler constant may include a pluralityof versions. As an option, the version may be selected utilizing aprecompiler macro. In another aspect, the precompiler constant is testedto determine a state of an apparatus on which the functions areexecuted. In such an aspect, the state of the apparatus may be based ona current bit size.

[7002] One example of a program that would use the aforementionedlibraries is as follows:

[7003] //---

[7004] ---

[7005] ---

[7006] #ifdef VERSION1

[7007] macro expr UnknownThing( a, b )=(a+b);

[7008] #elif defined(VERSION2)

[7009] macro expr UnknownThing( a, b )=(a@b);

[7010] #endif

[7011] //---

[7012] ---

[7013] ---

[7014] In use, a library with an unknown in it can be passed therein atcompile time to execute different functions. When a bit size goes abovea certain level, one may have to be able to process it differently. Assuch, a library is created containing different compile time functionsas separate macros. Users can set which macro is executed based on thestate of the system by testing a precompiler constant. Further, thepre-compiler macro may be used to select which version is utilized.

[7015]FIG. 87F illustrates a method 8790 for mimicking object orientedprogramming utilizing pointers in a programmable hardware architecture,in accordance with one embodiment of the present invention. Initially,in operation 8792, a structure is pointed to for executing a functioninvolving a structure. Thereafter, in operation 8794, contents of thestructure are analyzed. Further, at least one macro of a set of macrosis selected based on the analysis. See operation 8796.

[7016] When programming in C++, a person has some data with a hiddenpointer to the function. Then, whenever he or she has “this” pointer inHandel C, there is a structure of data that can be pointed at tofacilitate the function call.

[7017] Example;

[7018] A structure may be defined to have an integer therein. Two macrosare provided: one that increments and one that decrements. Based on thecontents of the integer, one can utilize the macros to provideincremental or decremental hardware. Further, one can utilize amultitude of these instances to have the macros work on the particularstructure, and emulate a hardware register.

[7019] When one opens a file in software, a handle for the file is used.Such handle may then be used for each call to the file to providecoordinated transfer of data to the file. The same type of structure maybe utilized in Handel C to facilitate transfer of data, and modificationof the data based on the correct hardware target.

[7020] This could be applied in any context. For example, a set ofmacros may be defined that contains a structure that has one or moresets of data. With respect to the User API structure, full functionpointers may be passed to something to invoke different structures andpass data back and forth. This allows something different to beexecuted.

[7021] More information regarding the foregoing concepts of FIGS. 87Bthrough 87F will now be set forth in greater detail.

[7022] An FPGA based co-processor provides a system with are-configurable sub-processor capable of providing a system with anotable performance increase. A host and client architecture may be usedto implement the co-processor system. The co-processor may functionprimarily as a client but may be capable of performing host operations,if the platform permits such operations. It may be possible for severalco-processors to exist in a system. An FPGA based co-processor may notoperate as a normal processor would. It may be capable of acting like aseparate system depending on the resources available to the FPGA. AnFPGA co-processor may also be able to perform complex operations on datawith only platform constraints restricting the data quantities handled.The operational functionality of an FPGA based co-processor may not beimplemented as sequences of instructions but by dedicated hardwarecircuits programmed into the FPGA device.

[7023] A host may make use of a client by making remote function calls.Co-processors may provide a multitude of re-configurable functionality.The functionality of the co-processor may be provided as a set offunctions. Each function may have a unique index to distinguish it fromother functions. Functions may normally be independent of each other andtotally platform independent. It may be possible for functions tointeract within a co-processor, this feature may be provided to thefunctions via a high level API. A function may have access to all sharedresources that the co-processor has available, this feature may beprovided to the functions via a high level API. To add new functionalityto a co-processor a designer may create a new function. The set offunctions available on a co-processor at any given time is entirely atthe engineers discretion.

[7024] The co-processor may be able to execute all available functionsconcurrently. This is a demonstration of the true parallelism thathardware provides. If it is required to execute the same function morethan once then multiple copies of the function may be required, eachwith a unique address. Creating multiple copies of a function is easilyachievable in Handel-C using function arrays.

[7025] Co-processor system functionality may be provided by a set ofAPIs. There may be a separate API for the host and client. Use of thetwo APIs may provide the user with total abstraction from the platform.This may allow platform independent code to be generated that interactswith the APIs. The APIs may manage all platform interaction and anycommunication protocols that are involved Host programs may be able touse the host API to execute functions on a co-processor. The clientco-processor may receive the messages from the host and stream data viathe client API to and from its functions as required. The functions mayinteract with the client API to access co-processor resources.

[7026] A host may interact with a clients a follows:

[7027] Begin the execution of a function

[7028] Send parameters to a function

[7029] Retrieve data from a function

[7030] Receive data ready notifications from a client

[7031] Perform auxiliary functionality

[7032] A client may interact with a host as follows:

[7033] Execute a function when instructed to do so.

[7034] Stream data to a function as required

[7035] Stream data from a function as required

[7036] Send data ready signals to a host

[7037] a Provide the address of the function that generated a data readysignal

[7038] Perform auxiliary functionality

[7039] The APIs may be designed to provide an abstraction layer forinterfacing software. This may allow user applications to be platformindependent in relation to the co-processor API.

[7040] Interfacing applications may not be aware of the standards orprotocols used by a host and client to communicate. The abstractionallows changes to the co-processor system to be made withoutsignificantly effecting user applications.

[7041] host (CPU) API Specification

[7042] The host API describes the software that may interact with userapplication running on the host platform.

[7043] The host API may provide a user with all the functionality theyneed to access and utilize an FPGA based co-processor. The host API mayrepresent an FPGA based co-processor as a set of remote functions. Theremay be sufficient functionality included in the host API to reduce theoverhead of a remote function call to a single standard local functioncall.

[7044] An application interfacing with the host API may be able toexecute remote functions using two possible methods; execute and wait orexecute and continue. The execute and wait mechanism may mimic a normalfunction call, it may not return until the remote function has completedexecution and the results have been retrieved. The execute and continuemechanism may allow several functions to be called without waiting forthe results of others.

[7045] The host API may notify user applications of events usingcall-back functions. The call-back functions may be executed when arelevant co-processor event occurs. Use of the execute and continuemechanism allows a function to produce interim results, i.e. producesmultiple completion signals with multiple data returns.

[7046] API Structure

[7047]FIG. 88 illustrates an application program interface 8800, inaccordance with one embodiment of the present invention. The host API8802 is designed to be constructed from two major sections 8804, 8806.The two sections are present to allow separation of the platformdependent code from the platform independent code. A library may bebuilt from each logical section of the design. This sectioning is doneto decrease the effort required to port the API between variousplatforms. The platform dependent section may provide a common interfaceand may functionally target the host platform. It may be possible tohave a variety of platform dependent sections available to providesupport for a variety of different target platforms.

[7048] The API design is layered to ease maintenance. Each layer mayrepresent a software library. Each library may provide a set offunctions and macros for use within the API core. Each layer may have acommon interface. Using common interfaces may increase the flexibilityof the API. The common interfaces may be used as templates for thelayers. New implementations can be based on the templates and providingthey are functionally compatible; they may be immediately compatiblewith existing systems.

[7049] Application Layer API Public Interface

[7050] The public interface provides the basic functions necessary for auser application to use an FPGA based co-processor.

[7051] Overlapped execution of remote functions can be achieved bydirectly accessing the physical layer interface and initiating datatransfers to functions.

[7052] Call-back functions are used to implement an event driven system.The call-back functions are executed to inform the user application whenevents have occurred. Call-back functions may be repeatedly useddepending on the nature of the event. The last event to be signaledbefore a transfer is completed would normally be a completion statusreport or a fatal error. Data is transferred to a call-back function inthe form of results structure.

[7053] Legacy styled remote function executions are performed usingExecuteFunction Wait. More advanced and overlapped remote functionexecution is performed using ReadData and WriteData. API PublicFunctions TransferResultsStructure ExecuteFunctionWait(  unsigned intFunctionIndex, unsigned int DataAmountParameters, char*parameterDataBuffer unsigned int ReturnDataAmount, char*ReturnDataBuffer, Parameters FunctionIndex Index of the function to beexecuted. DataAmountParamaters Size of the parameter data buffer inbytes. ParameterDataBuffer A data buffer containing the parameters tosend to the function to be executed. ReturnDataAmount Size of the returndata buffer in bytes. ReturnDataBuffer A data buffer to store the returndata from the function to be executed.

[7054] Return Value

[7055] The structure returned from this function may contain informationabout the completion results for the remote function execution.

[7056] Remarks

[7057] ExecuteFunction Wait is used to perform a legacy styled functioncall. The specified remote function may be executed and the contents ofParameterDataBuffer may be transferred to the function. When the dataready signal from the executed from is received the return data may betransferred and stored in the ReturnDataBuffer. This method of remotefunction execution can only be used on remote functions that have atraditional execution flow. FIG. 91 shows a traditional execution flowfor a remote function. The host API may require certain tasks to beperformed before any interaction with a co-processor occurs.StartCoprocessorSystem is provided by the host API for user applicationsto initialize the host APIs subsystems.

[7058] void StartCoprocessorSystem( . . . );

[7059] Parameters

[7060] Remarks

[7061] Initializes the API, allocates required system resources. Thismay be called before any other API function.

[7062] To enable a graceful shut down the host API may provide a userapplication with a method for informing it that it is no longerrequired. ShutdownCoprocessorSystem is provided by the host API as theshutdown function for the co-processor system.

[7063] void ShutdownCoprocessorSystem( . . . );

[7064] Parameters

[7065] Remarks

[7066] Call this when the API functionality is no longer required. Thismay clean up any system resources being used by the API.

[7067] Physical Layer API Public Interface

[7068] The physical layer interface provides access to platformdependent features. The features that form the public interface for thephysical layer enable a user to perform more advanced functionality thanis possible with the application layer public interface.

[7069] As an FPGA is a re-configurable device a method for configuringthe device is required. This is provided by the physical layer publicinterface. Physical Layer Public Functions intConfigureCoprocessor(  char *BitFile ); Parameters BitFile Name of a‘.bit’ file to be loaded into the FPGA co-processor.

[7070] Return Value

[7071] If the function succeeds the return value is nonzero.

[7072] If the function fails the return value is zero.

[7073] Remarks

[7074] The ‘.bit’ file used may be compatible with the target FPGAdevice. The client API provides the means to design an FPGA basedco-processor in Handel-C. Compiling Handel-C code to EDIF may enable tocreation of a ‘.bit’ file using the FPGA vendors software tools.

[7075] An FPGA co-processor is capable of supporting advancedfunctionality. For a user application to use advanced features it may becapable of transferring data from a co-processor whenever it needs to.unsigned int ReadData(  TransferConfiguration Configuration );Parameters Configuration A structure that contains all the required datato begin the operation.

[7076] Return Value

[7077] The return value is a unique identifier for the operation. Theidentifier may be used during informative communication.

[7078] Remarks

[7079] This function may transfer data to a remote function. If thetarget function is not executing it may be executed.

[7080] An FPGA co-processor is capable of supporting advancedfunctionality For a user application to use advanced features it may becapable of transferring data to a co-processor whenever it needs to.unsigned int WriteData(  TransferConfiguration *Configuration );Parameters Configuration A structure that contains all the required datato begin the transfer.

[7081] Return Value

[7082] The return value is a unique identifier for the transaction.

[7083] Remarks

[7084] This functions may transfer data from a remote function.

[7085] A user application may want to monitor the progress of an activetransaction. The host API provides the QueryTransaction function fortransaction monitoring purposes. TransferResultsStructureQueryTransaction( unsigned int UniqueIdentifier ) ParametersUniqueIdentifier The identifier is used to provide a unique handle foreach transaction.

[7086] Return Value

[7087] The structure returned from this function may contain informationabout the transaction being queried.

[7088] Remarks

[7089] Use this function to get intermediate results for an activetransaction.

[7090] Call Back Functions and Structures

[7091] Call back functions are used throughout the API to prevent theneed for polling. The use of call back function builds an event drivensystem. When event occur the call back functions are executed tocommunicate information about the event. Typical events may be transfercompletion, error notification and timeout.

[7092] Structures

[7093] Several of the physical layer functions require configurationdata. The Configuration structure provides encapsulation for theconfiguration data. struct Configuraion{void(*TranferCallback)(TransferResultsStructure TransactionInfomation);unsigned int DataQuantity; unsigned char *DataBuffer; unsigned intDestinationAddress; unsigned int MaxDesiredTransactionTime; }

[7094] Members

[7095] PhysicalLayerEventHandler

[7096] This is the call-back function that is exclusive to the physicallayer. The user should create this function and it should be based onthe function prototype TransferCallback.

[7097] DataQuantity

[7098] This value refers to the amount of data in bytes to betransferred.

[7099] DataBuffer

[7100] A pointer to a data buffer, if receiving data the buffer may beat least as big as DataQuantity bytes.

[7101] DestinationAddress

[7102] The destination address refers to the index of the function towhich the data is to be transferred.

[7103] MaxDesiredTransaction Time

[7104] This value specifies a length of time in milliseconds. It is usedto indicate the maximum desired time for a transaction. This allowstransactions to be aborted if they are taking to long.

[7105] Remarks

[7106] The configuration structure is used when calling functions in thephysical layer.

[7107] The status results for a particular function are encapsulated inthe TransferResultsStructure. This structure is commonly passed tocall-back function but is also used by QueryTransaction. structTransferResultsStructure{ unsigned int UniqueIdentifier; unsigned intQuantityOfDataTransferred; TransferResultsCodes ResultCode; }

[7108] Members

[7109] QuantityOfDataTransferred

[7110] This value is used to indicate how many bytes were successfullytransferred.

[7111] ResultCode

[7112] The result code may be on of the defined states for theenumerated data type TransferResultsCodes.

[7113] Remarks

[7114] The transfer results structure contains information about arecent transfer request.

[7115] Possible values for the status codes are pre-defined using anenumerated data type. enum unsigned int TransferResultsCodes ={  CPS_COMPLETED=0,   CPS_FATAL,   CPS_TIMEOUT,   CPS_SYSTEM_BUSY,  CPS_IN_PROGRESS,   CPS_ON_HOLD };

[7116] Remarks

[7117] The results codes are used by the system to indicate transactionresults.

[7118] Callback Functions

[7119] Transfer call-back functions are used to generate the eventdriven system. They are user created function that are passed to theAPI, they may be based on the TransferCallbackfunction prototype.

[7120] void TransferCallback(const TransferResultsStructureTransactionResults)

[7121] Parameters

[7122] TransactionResults

[7123] This is a structure that contains information about the reasonfor executing the call-back function. The transaction is only terminatedwhen one of CPS_COMPLETED, CPS_FATAL or CPS_TIMEOUT is indicated as theresult code.

[7124] Remarks

[7125] The transfer call back function is used as the event handler fora transaction. The user may provide this function if they requireoverlapped co-processor operations.

[7126] Host Communication With a Client

[7127] The methods a host uses to transport data to and from a clientare very platform dependent.

[7128] Client (FPGA) API Specification

[7129] The client API deals with the FPGA portion of the co-processorsystem. Everything described here refers to the hardware required toconstruct an FPGA based co-processor. Many of the descriptions used inthis section use software terminology; this is possible due to theHandel-C programming language that allows hardware to be describe interms of algorithms using a C styled syntax.

[7130] API Structure

[7131] The client API may consist of macros and functions for twopurposes.

[7132] The development of functions that a host may access and execute.

[7133] The construction of the hardware required to interact with a hostand the platform resources.

[7134] To ensure maximum maintainability the client API may be dividedinto two major sections. The two sections are created to separateplatform independent code and platform dependent code.

[7135] The platform independent section has been named the ‘applicationlayer’. The platform dependent section has been named the ‘physicallayer’. The physical layer may form the ‘physical layer library’. Theapplication layer may form the ‘application layer library’.

[7136] The client API may enable a user to create hardware for use by ahost using Handel-C and representing the hardware as Handel-C functions.The user created hardware for host use may be called ‘user functions’.One can apply software terminology to the hardware due to theabstraction that the Handle-C language provides.

[7137] The application layer may contain macros and functions that areused by user functions. The application layer may provide user functionswith a layer of total platform abstraction. This may allows userfunctions to be designed once for any platform.

[7138] A user may use the API libraries to construct a ‘physical core’and one or more ‘user cores’. The purpose of a user core may be toreference the user functions and associate the user functions withindexes using platform independent methods.

[7139] The purpose of the physical core is to provide a separate filethat a user can use to interact with the platform. This may allow thework required to port a co-processor to be limited to only minormodifications of the physical core.

[7140] Configuration of platform resources may be possible using thephysical layer of the API when creating a physical core.

[7141]FIG. 89 illustrates a schematic 8900 showing that the physicallayer 8902 is divided into a farther two sections, 8904 an 8906, inaccordance with one embodiment of the present invention. Sharedresources are handled by section 2 of the physical layer and hostinteraction is handled by section 1 of the physical layer. The twosections of the physical layer are accessible through a commoninterface, the ‘physical layer platform independent interface’. A commoninterface 8908 for the physical layer is defined to ensure thatdifferent implementations (for different platforms) of the physicallayer are compatible with the application layer 8910.

[7142] User functions gain access to the application layer API via theparameters passed to the function when it is executed. This may allowthe API libraries to distinguish between user functions when APIfunction calls are made. The concept of executing a hardware functionrelates to a signal changing to indicate ‘go’.

[7143] A situation may arise where a user function requires directaccess to auxiliary I/O on a particular platform. A user function may beable to access auxiliary I/O by accessing a set of macros that formconnections to the auxiliary I/O. Use of auxiliary I/O may compromisethe portability of a user function but the auxiliary I/O system may bedesigned to minimize the impact.

[7144] The purpose of the physical layer is to provide some abstractionfrom platform features. This may allow the application layer to expectfrom the physical layer a common interface with relatively commonfeatures. A physical layer library may be constructed for each targetplatform. The physical layer libraries may contain a set of macro basedon the common template provided in the design of the physical layer. APIusers may be able to create the top level of a co-processor using therelevant API physical layer library.

[7145] Use of the Client API Libraries-

[7146]FIG. 90 is a schematic diagram 9000 of the application layer 9002,physical layer 9004, and user domain 9006, in accordance with oneembodiment of the present invention.

[7147] The API libraries may provide layers of abstraction to make aco-processor as portable as possible. Any parts of the system thatinteract solely with the application layer can be considered totallyplatform independent as the application layer is its self totallyplatform independent.

[7148] User functions may interact with the application layer libraryusing the user function header. The user function header may prototypethe API functions that may be passed to a user function when it isexecuted. The API functions may be encapsulated into a structure and thestructure may be passed to the user function when it is executed. Thismechanism is used to ensure forward compatibility and to allow theapplication layer library to distinguish between the user functions inthe most efficient method possible.

[7149] User cores may be created using the macros of the applicationlayer library. When a user core is constructed the user may referencethe functions that may form the co-processor functionality. Indexes maybe assigned to the user function when the user core is created.

[7150] The purpose of the physical layer library is to provide a commoninterface to the platform features. Due to the possible diversity of thefeatures a platform may provide a physical layer library may be createdfor each platform to be supported. This may allow people who use thephysical layer libraries to do so knowing that their co-processor may beeasy to port to other platforms. The physical layer library is veryplatform dependent but is intended to enable a user to create a physicalcore that is not very platform dependent.

[7151] Creation of a Co-Processor

[7152] To build a co-processor may require a user to generate severalfiles using the API libraries. User functions may use the APIs userfunction header to access API functionality. The actual co-processor isbuilt by the user creating a physical core. The user may also create atleast one user core to accompany the physical core. The user core may beplatform independent as it may only interact with the application layersection of the API. The physical core may be classed as platformdependent but the API may provide some abstraction via the physicallayer allowing rapid porting of a physical core. The user can configurevarious features of a platform during creation of a physical core.

[7153] The physical core forms the top level for a co-processorimplementation.

[7154] File Associations

[7155]FIG. 90 shows the files that may be required to construct an FPGAbased co-processor, in accordance with one embodiment of the presentinvention.

[7156] The uses tags are numbered to allow explanation of theinterconnections. See FIG. 90 for the numbered uses tags. A usersphysical core may include the physical layer library header to gainaccess to the physical layer library. The physical layer library headermay contain declarations that may reference the public contents of thephysical layer library. A user physical core should include the systemconfiguration header file. When the physical layer library macros areused they may use the configuration data. A users physical core may beable to link to a number of user cores. A users physical core mayprovide a user core with a clock and the relevant functionality toenable its operation. The user function header links to the physicallayer library to gain access to the names of the auxiliary 1/ O ports. Auser core may include the application layer library header to gainaccess to the macros in the application layer library.

[7157] The application layer library header may contain declarationsthat link to the macros and functions in the application layer library.The user function header links to the application layer library toprovide user function with access to the API. A user core may link to atleast one user function. User functions may include the user functionheader to gain access to the API.

[7158] Co-Processor System Configuration

[7159] The co-processor API support a large amount of configurationoptions. The platform configuration may be performed when the user iscreating the physical core. The user function index maps are createdwhen the user create a user core.

[7160] Common platform configuration options supported by the physicallayer library (used when a user is creating a physical core):

[7161] Number of functions supported. This may configure how the hostaddress decoder is built. The size and speed of the address decoder isdependent on the number of functions to be supported. The addressdecoder may use advanced techniques therefore the index map seen by thehost may not be incremental. Address to function index maps may bedefined.

[7162] Configuration of the platform memory banks. Memory banks may beconnected directly to the FPGA or accessed via the local bus. Thephysical layer library may manage any specifics. The user may be able toconfigure which memory banks map to which functions and if the memorybanks are shared or dedicated.

[7163] Type and buffering mode of the mailboxes.

[7164] Type and size of message queue to the host.

[7165] Common configuration options supported by the application layerlibrary (used during the creation of a user core):

[7166] Index associated with a particular function.

[7167] Application Layer User Core Creation InterfaceCoProcessorInitialiseSystem( UserCoreName ); Parameters UserCoreNameThis should be a unique name for the user core. This name may bereferenced by the physical core to make the necessary connection.

[7168] Remarks

[7169] This is pre-compiler macro, it should be used at global scope. Itshould be used after the header is included for the application layerlibrary. It performs the necessary definitions and declarations requiredfor the user core. CoProcessorAssociateFunction(  UserCoreName,FunctionIndex, FunctionPointer ); Parameters UserCoreName This should bea unique name for the user core. This name may be referenced by thephysical core to make the necessary connection. FunctionIndex This isthe index that may be used by the host to transfer data to the functionbeing configured. FunctionPointer This is a pointer to the user functionthat is being associated with the specified index.

[7170] Remarks

[7171] This is a Handel-C macro procedure. It should be called withinthe main function of a user core. It is used to assign an index to afunction. CoProcessorStart(  UserCoreName ); Parameters UserCoreNameThis should be a unique name for the user core. This name may bereferenced by the physical core to make the necessary connection.

[7172] Remarks

[7173] This is a Handel-C macro procedure. It should be the last callmade to any of the co-processor system macros. It should be located inthe main function of a user core. It may become the main handler for allphysical core interaction. This macro may never return as it may containa forever loop.

[7174] Application Layer User Function Interface

[7175] The majority of the application layer API is provided to a userfunction via a parameter passed to the user function when it isexecuted. The parameter is a structure. The structure may contain a setof function pointers. Passing a structure to a user function allow forforward compatibility. If at a later stage more functions need to beadded to the API this can be done without effecting existing userfunctions. The API may expect a user function prototype to look likethis: void UserFunctionName(  USER_API ParameterName );

[7176] Remarks

[7177] UserFunctionName and ParameterName can be replaced with any legalC styled name. This is the USER_API structure: typedef struct{ void(*CoProcessorSetAddress)(unsigned int 32 Address, unsigned int 1ReadOrWrite); void (*CoProcessorDoTransfer)(unsigned int 32 *Data); void(*CoProcessorGetData)(unsigned int 32 *Data); void(*CoProcessorSendData)(unsigned int 32 Data); void(*CoProcessorNotifyDataReady)(); unsigned int 1(*CoProcessorCheckForPost)(); unsigned int 32(*CoProcessorGetSendersAddress)(); void(*CoProcessorSetPostAddress)(unsigned int 32 Address); void(*CoProcessorDoPostDataRead)(unsigned int 32 *Data); void(*CoProcessorDoPostDataWrite)(unsigned int 32 Data); } USER_API;

[7178] Members

[7179] CoProcessorSetAddress

[7180] This function is used to initiate a memory data transfer. Itallows an address to be set and the direction of the transfer to beconfigured. Memory access is pipe-lined and it takes more than one clockcycle for a transaction to be completed. Separation of the address anddata phase allows burst mode transactions to be performed. The exactnumber of cycle it takes for a memory operation is dependent on theplatform; to compensate for this CoProcessorDoTransfer may always ensuresynchronization between the memory address phase and data transfer. Theaddress phase is buffered to enable one address value to be written forevery available memory address cycle. CoProcessorSetAddress may block ifit has been called to many times before a call of CoProcessorDoTransfer.Memory address and data phases can be interleaved to provide a highmemory bandwidth.

[7181] CoProcessorDoTransfer

[7182] This function is provided to handle the data phase of a memoryaccess. It may block until a previous address phase has completed.

[7183] CoProcessorGetData

[7184] CoProcessorGetData gives a user function the ability to retrievedata from the host. This function may block until the host sends data.

[7185] CoProcessorSendData

[7186] CoProcessorSendData gives a user function the ability to senddata to a host. This function may block until the host requests datafrom the function.

[7187] CoProcessorNotifyDataReady

[7188] This function is used by a user function to notify the host thatdata is ready. This may be used as required and is not restricted toonly meaning data is ready.

[7189] CoProcessorCheckForPost

[7190] Used by a user function to test for the presence of post in themailbox.

[7191] CoProcessorGetSendersAddress

[7192] Used to get the address of the sender of the data currently inthe mailbox. This function should be called in parallel with or beforeCoProcessorDoPostDataRead.

[7193] CoProcessorSetPostAddress

[7194] Initiates the sending of mail. The address is configured for thesending and the next data to be sent may be forwarded to the addressspecified here.

[7195] CoProcessorDoPostDataRead

[7196] Gets data from the mailbox. This function may block if no data iswaiting.

[7197] CoProcessorDoPostDataWrite

[7198] Sends data to a previously specified address. If an address hasnot been specified this function may block until an address isspecified.

[7199] Remarks

[7200] The only part of the user API that is not provided to functionsthrough the structure is access to auxiliary I/O. Macros are used toestablish the links between a user function and auxiliary I/O. Thismethod is used to allow a function direct access to auxiliary I/O withno interference from the core of the client API. Access to auxiliary isdeemed to be necessary as the nature of the devices connected toauxiliary is unknown to the API. User API functions in detail: voidCoProcessorSetAddress(unsigned int 32 Address, unsigned int 1ReadOrWrite ); Parameters Address The address parameter represents thememory location for the target operation. ReadOrWrite Indicates the modefor the memory operation, an active high signal indicates a readoperation.

[7201] Remarks

[7202] CoProcessorSetAddress is used to initiate a memory accessoperation. Memory access operations are separated into the address phaseand data phase. The phase separation allows the system to achievemaximum bandwidth utilization. void CoProcessorDoTransfer(  unsigned int32 *Data ); Parameters Data A pointer to a register. The register may beloaded or read depending on the mode selected during the synchronizedaddress phase. Synchronisation is performed by the system.

[7203] Remarks

[7204] CoProcessorDotransfer is used to perform the data phase for amemory access operation. This function may automatically synchronizewith the address phase. void CoProcessorGetData(  unsigned int 32 *Data); Parameters Data A pointer to a register, the register is loaded witha data parameter sent by the host.

[7205] Remarks

[7206] CoProcessorGetData may lock until data has been sent by the hostand target for the user function using its copy of this function. voidCoProcessorSendData(  unsigned int 32 Data ); Parameters Data The datathat may be transferred to the host when it requests data from the userfunction.

[7207] Remarks

[7208] CoProcessorSendData may block until the host request data fro theuser function using its copy of this function.

[7209] void CoProcessorNotifyDataReady();

[7210] Remarks

[7211] A user function should use this function to notify the host thatis wants to perform a data transfer operation.CoProcessorNotifyDataReady may send some form of interrupt to the host,the signal may be queued if other user functions are signaling at thesame time.

[7212] unsigned int 1 CoProcessorCheckForPost();

[7213] Return Value

[7214] The return value is active high to indicate that post is waiting.

[7215] Remarks

[7216] CoProcessorCheckForPost is used for testing the incoming mailboxfor any contents.

[7217] unsigned int 32 CoProcessorGetSendersAddress();

[7218] Return Value

[7219] The return value may be the function index of the function thatsent the mail waiting in the mailbox.

[7220] Remarks

[7221] The mailbox is only emptied by CoProcessorDoPostDataReadtherefore repeated calls to CoProcessorGetSendersAddress may return thesame result until the waiting mail has been retrieved. This function mayblock if there is no mail waiting in the mailbox. voidCoProcessorSetPostAddress(  unsigned int 32 Address ); ParametersAddress The address parameter represents the user function index for theuser function that may receive mail sent by the user of this function.

[7222] Remarks

[7223] CoProcessorSetPostAddress configures the destination address forthe mail to be sent. This function only needs to be used to set thedestination at the beginning of a multi message transfer.

[7224] This should be called a clock cycle before writing the dataintended for the address being programmed. voidCoProcessorDoPostDataRead( unsigned int 32 *Data ); Parameters Data Thisis a pointer to a register. The data from the mailbox may be written tothe pointed to register.

[7225] Remarks

[7226] CoProcessorDoPostDataRead may send mail to the address that iscurrently configured. It is not necessary to set the address for everymail message sent, the previous address may be used. voidCoProcessorDoPostDataWrite( unsigned int 32 Data ); Parameters Data Thismay be sent to the addressed user functions mailbox.

[7227] Remarks

[7228] CoProcessorDoPostData Write may send mail to the address that iscurrently configured. It is not necessary to set the address for everymail message sent, the previous address may be used.

[7229] This function may block if the recipients mailbox is full. Thecapacity of the mailbox is platform dependent.

[7230] API User Function Interface (Auxiliary I/O)

[7231] Auxiliary I/O is provided to user functions to allow a user totake advantage of any platform features that are outside the scope ofthe application API. These features are represented as the pinconnections that the external features/devices are connected to. The APImay make no attempt to translate or shield the user from auxiliary I/O.Access to auxiliary is direct and provided on an ‘as is’ basis.

[7232] The application layer API provides access to auxiliary via a setof macros. Auxiliary I/O ports are named and may be platform specific.The definitions for auxiliary I/O is stored in the physical layerlibrary. The auxiliary I/O section of the application layer API providesaccess to the physical layer library information. When physical layerlibraries are created the details of auxiliary I/O should be publishedwith the library. The application layer provides access to the physicallibrary in this way in an attempt to reduce the amount of effortrequired to port user functions that are dependent on platform specificfeatures.

[7233] Auxiliary I/O should only be used in a direct one to onerelationship with a user function. If more than one user functionrequires access to a shared resource a service user function should bedeveloped. Other user functions can then communicate with the serviceuser function using the mail box system. This may make only the servicefunction directly dependent on the auxiliary I/O, thus reducing theamount of effort required during porting. These are the API auxiliaryaccess macros: CoProcessorConnectReadAUX(  PortName ) ParametersPortName This should be the name of an I/O port.

[7234] Remarks

[7235] This is a pre-compiler macro and should be used at global scope.It declares a read port for auxiliary I/O. This macro may write afunction that provides the functionality to read the named I/O port.Access to the function is provided by the CoProcessorAuxRead macro.CoProcessorConnectWriteAUX(  PortName ) Parameters PortName This shouldbe the name of an I/O port.

[7236] Remarks

[7237] This is a pre-compiler macro and should be used at global scope.It declares a write port for auxiliary I/O. This macro may write afunction that provides the functionality to write to the named I/O port.Access to the function is provided by the CoProcessorAuxWrite macro.CoProcessorConnectWriteAUX(  PortName ) Parameters PortName This shouldbe the name of an I/O port.

[7238] Remarks

[7239] This is a pre-compiler macro and should be used at global scope.It declares a port for auxiliary I/O that is bi-directional. This macromay write functions that provide the functionality to read, write andset the output buffer mode for the named I/O port. Access to thefunction is provided by the CoProcessorAuxRead, CoProcessorAuxWrite andCoProcessorAuxSetEnable macros. CoProcessorAuxRead(  PortName, unsignedint *Data ) Parameters PortName This should be the name of an I/O port.Data This is a pointer to a register. The register may be loaded withthe value currently on the I/O port.

[7240] Remarks

[7241] This is a Handel-C macro expression. It is created when readfunctionality is required on an auxiliary I/O port. The bit width ofData may match the port width. The bit width of the port can bedetermined using the CoProcessorPortWidth macro.AuxSetWriteReg(  PortName, unsigned int *Data ) Parameters PortName Thisshould be the name of an I/O port. Data Data should be a pointer to aregister.

[7242] Remarks

[7243] This is a Handel-C macro procedure. It is created when writefunctionality is required on an auxiliary I/O port. The bit width ofData may match the port width. The bit width of the port can bedetermined using the CoProcessorPortWidth macro. Data may become theoutput for the I/O port. CoProcessorAuxSetEnable(  PortName, unsignedint 1 Enable ) Parameters PortName This should be the name of an I/Oport. Enable The enable signal is used to set the mode for the outputbuffers. If Enable is active the output buffers are set to a highimpedance more.

[7244] Remarks

[7245] This is a Handel-C macro procedure. It is created when read andwrite across an auxiliary I/O port is required. This macro is used toaccess the enable function created when I/O is mapped.CoProcessorPortWidth(  PortName ) Parameters PortName This should be thename of an I/O port.

[7246] Remarks

[7247] This is a pre-compiler macro that can be used anywhere. It is autility macro that allows access to the width of an auxiliary I/O port.This is useful when defining variables that connect to a port.

[7248] Physical Layer Interface

[7249] A common interface for the physical layer is defined to ensurethat all implementations of the physical layer are compatible with theapplication layer. The physical layer interface may allow theconfiguration and creation of the hardware necessary to manage:

[7250] Memory

[7251] Primary bus interface

[7252] System clock synchronization

[7253] Co-Processor Construction Macros

[7254] CoProcessorBuild( )

[7255] Remarks

[7256] This is a pre-compiler macro. It should only be used at globalscope. It may construct the necessary connection to the local bus andany other platform specific definitions.

[7257] CoprocessorActivate( )

[7258] Remarks

[7259] This is a Handel-C macro procedure. It should only be used atlocal scope, preferable in a main function. It may activate any platformspecific background handler tasks.CoProcessorSetUserCoreClock(  UserCoreName, UserCoreClockSource )Parameters UserCoreName This may be the name given to a user core whenit was created. UserCoreClockSource This may be one of the availableclock sources defined for the platform.

[7260] Remarks

[7261] This is a pre-compiler macro. It should only be used at globalscope. This macros may be used to configure the clock source for a usercore. It may be possible for a user core to be clocked at a differentrate to the physical core. This is only possible if the physical layerlibrary for the target platform provides more than one clock source.CoProcessorCreateUserFunctionPort(  UserCoreName, DesiredHostAddress,UserCoreFunctionIndex, InitialMemoryAccessController, PostalAddress )Parameters UserCoreName This may be the name given to a user core whenit was created. DesiredHostAddress This is the address that an externalhost may use to access the user function being setup.UserCoreFunctionIndex This is the unique index that is used internallyby the user core to identify the user function.InitialMemoryAccessController This is the index of the memory accesscontroller that may be initially associated with the user function.PostalAddress This is a unique identifier that other user functions canuse to send messages to the user function being configured.

[7262] Remarks

[7263] Any user function that is to be used by a host may be setup usingthis macro.

[7264] Memory Bank Construction Macros

[7265] The memory ports are constructed in the physical core. Thisallows the memory access controllers to run faster than the userfunctions. Memory controllers are device specific and may be configuredas dedicated or shared. When a memory bank is shared the number of portsto be created may be defined.

[7266] Memory management units may be constructed by referencing a banksname. The names given to the memory banks may be a platform constant andmay be located in the physical layer library. Memory banks should beconstructed before the system handlers are initiated.CoProcessorBuildDedicatedMemoryController(  BankName,MemoryBankUniqueIdentifier ) Parameters BankName The name of a memorybank. MemoryBankUniqueIdentifier This is a unique identifier for thememory bank. It may be required when configuring user functions.

[7267] Remarks

[7268] This macro is a pre-compiler macro. It should only be used inglobal scope. It constructs a set of functions that form a memorymanagement unit for the named memory bank. The method of memorymanagement used is single port exclusive therefore the MMU is a simpletransaction sequencer.CoProcessorBuildMultiPortMemoryController(  BankName, NumberOfPorts )Parameters BankName The name of a memory bank. NumberOfPorts The numberof ports to generate.  This represents the number of duplicate functionsto create.

[7269] Remarks

[7270] This macro is a pre-compiler macro. It should only be used inglobal scope. It constructs a set of functions that form a memorymanagement unit for the named memory bank. A multi-port MMU isconstructed that sequences memory requests and provides simplearbitration for the available ports. Semaphores are created and theaccess functions are constructed as an array of functions.CoProcessorSetPortUniqueIdentifier(BankName, BankPortIndex,UniqueIdentifier ) Parameters BankName This is the name of the bank thatis being referred to. BankPortIndex This refers to the particular porton the multi-port mem UniqueIdentifier

[7271] Remarks CoProcessorActivateMMU( BankName ) Parameters BankNameThe name of a memory bank.

[7272] Remarks

[7273] This macro should be called within the main function of thephysical core. It starts any background memory management functions thatmay be required.

[7274] Physical Layer, Connection to Host

[7275] The actual data transfer between a host and an FPGA is platformspecific and is beyond the scope of the specification for the API for aco-processor.

[7276] The physical layer may not be restricted to using any particularmethod or protocol for communicating with a host. The only constraint isthat the host may be capable of ‘speaking the same language’ as the FPGAco-processor.

[7277] The link between a host and client may be capable of performingseveral basic signaling functions:

[7278] An address should be associated with any data transferred.

[7279] A client may be able to send a signal to a host to inform thehost that the client is ready to perform some form of data transfer.

[7280] In an environment where more than one host is present the clientmay be able to distinguish between each host and have the capability ofsignaling to a host exclusively and directly.

[7281] If client mode host functionality is required the client may beable to request access to the data transfer medium.

[7282] Physical Layer, Shared Resources

[7283] The API may provide management of the shared resources. This mayprimarily involve mutual-exclusion enforcement. Further extensions mayprovide features such as a static or a dynamic MMU. The auxiliarycommand system may provide access to features such as bank switching ora dynamic MMU.

[7284] Auxiliary I/O may be provided via an I/O mapped system. Userfunctions may use a set of macros to generate functions to access agiven auxiliary I/O port. Auxiliary I/O ports may be defined in theheader file provided for accessing the user function macros. Whendeveloping a new platform auxiliary I/O should be named and the portsdefined in the physical library.

[7285] When building a co-processor one step may be to configure themethod used to access any available memory banks. This configurationstep may usually only be done once for a platform unless the memory bankconfiguration needs to be changed. It may be possible to configure amemory bank as a dedicated bank or a multi-port bank. The option for adedicated or multi-port RAM bank is given to allow a function to haveexclusive access to a memory bank or to allow several functions to shareaccess to a memory bank. When the library for a new platform isdeveloped each memory bank may be given a unique name.

[7286] Getting Data From the Host

[7287] A client is not capable of requesting data from the host. Aclient function can use the GetData function to wait for the host tosend data. The GetData function may block until the host transfers datato the client function.

[7288] Sending Data to the Host

[7289] A client cannot directly initiate a data transfer to the host. Aclient can notify the host that it has data ready to transfer.NotifyDataReady( ) is used to get the attention of the host. A clientcan never initiate a data transfer, using the notification function maysignal to a host that one wants to transfer data. How the hostinterprets the signal is dependent on the host application.

[7290] Use SendData to perform the actual transfer of data. Thisfunction may block until the provided data has been transferred. Datatransfers are never initiated by the client. This function shouldnormally only be used after sending a data ready notification.

[7291] Inter-Function Communication

[7292] A function may be capable of sending a message to anotherfunction. To do this a function may need to know the address of thedestination function. Inter function communication is achieved usingmailboxes. A mailbox is a pair of registers. One register may be usedfor sending mail and the other for receiving mail. A flag may be used toindicate when new mail has arrived. A function should monitor the flagto determine when mail has arrived. The flag may be active when new mailis in the mailbox. If after a read of the mail box the flag is stillhigh then new mail has already arrived i.e. the flag is an active highsignal.

[7293] Client Mode Host Operations

[7294] A user function can perform host type operations. The hostoperating mode is enabled using the mail delivery system. Posting amessage to address zero may allow a function to execute a function as ifit were a host. The data may represent the index of the function thatmay receive communication. This functionality may also allow the remoteexecution of a function; providing that the platform supports this typeof operation. The MSB of the data is used to distinguish betweeninternal and remote function executions. If the MSB is set then remoteexecution mode is selected. Once this posting has been sent the SendDataand GetData functions may be re-directed to the specified function. Torestore normal operation of the SendData and GetData functions a messageshould be posted to address zero with the data set to zero.

[7295] Co-Processor User Functions

[7296] A co-processor function may be self contained within the Handel-Cfunction construct. A function may interact with the system via theclient user API. Every user function may accept the same parameter Theparameter may be a pointer to a structure that contains pointers to theuser API functions. The only exception may be auxiliary I/O access. Fora function to gain access to auxiliary requires that the auxiliary I/Omacros are used, the only part of the API that is publicly visible to afunction.

[7297]FIG. 91 shows a typical execution flow 9100 for a function. Uponexecution the function gathers its parameters in operation 9102, it thenperforms a processing operation 9104 and returns the results to the hostin operation 9106. FIG. 91 is only an example since the functions do nothave to execute in this manner.

[7298] Host and Client Interaction Specification

[7299] The particular protocol used when a host and client communicateis not constrained. What is specified is the meanings of the messagesthat are communicated between a host and a client.

[7300] Basic Message Format

[7301] A host may always be the master in a communication, therefore ahost may always initiate a data transfer between a host and a client.All messages from a host to a client may consist of an address with somedata. The only messages that a client can send to a host is an attentionmessage¹, this message may carry no address or data Host messages may bedata read operations or data write operations. The host can use anaddress of zero and the address MSB to send auxiliary commands to aclient (see 0).

[7302] Address Zero

[7303] Address zero is reserved for system use. Address zero is the onlyaddress that is reserved by the system and cannot be used as an indexfor a client user function. A host may use address zero to query theclient when an attention message is received.

[7304] A host may send a read message with address zero to a client toretrieve the reason for the attention message sent by the client. Thedata read from the client may be an address, the MSB of the address isused as a modifier (see 0).

[7305] Address zero is used internally in a client to distinguishbetween function indexes and internal system requests.

[7306] A host can use address zero with the MSB modified (see 0) torepresent an auxiliary command.

[7307] Address MSB

[7308] Typically the address MSB may be used as an address modifier bit.If a platform supports an alternative method of achieving the followingthen the address MSB can be used for regular use. The address MSB isused to modify the meaning of the address.

[7309] A host uses the MSB modifier (set to ‘1’) in conjunction withaddress zero to distinguish between signal reason requests and auxiliarycommand.

[7310] A host does not use the MSB modifier in normal communications sothe MSB should be set to ‘0’.

[7311] A client uses the MSB modifier internally to distinguish betweeninternal (MSB set to ‘0’) addresses and external (MSB set to ‘1’)addresses.

Detailed Design

[7312] Host and Client Interaction

[7313] The communication protocol used to transfer between host andclient is not constrained by this design. This design does constrain themeaning of the data transferred between host and client.

[7314] The actual method of data transfer used between a host and clientmay depend on the system platform.

[7315] The host may see the FPGA co-processor as an addressable device.An FPGA co-processor device may treat each available address as a dataport. To interact with an FPGA co-processor device the host may read andwrite data to the available ports.

[7316] Basic requirements for host/client communication:

[7317] Address zero is reserved for system use.

[7318] An address may always be associated with data.

[7319] An address always refers to an existing function index or addresszero.

[7320] The most significant 8 bits of the address is reserved by thesystem and is used as an address modifier bit.

[7321] Data Transfer Mechanism

[7322] To transfer or read data from a function a host should perform aread or write operation to the address it requires data from. Datashould be streamed to an address as an address does not representregisters i.e. repeated reads or writes to the same address. Addressesshould not be incremented when data is read or written as this wouldaddress other functions.

[7323] Parameters are passed to a function by performing a writeoperation to the functions index address. Data is returned from afunction by reading from the functions index address. The amount of datatransferred is dependent on the design of the co-processor function. Thehost may know how much data to transfer or use the data beingtransferred to indicate how much data may be transferred.

[7324] Read and write operations can be interrupted and resumed by thehost at any time. This is possible due to the slave nature of a clientdevice. Remote functions on the co-processor may wait while the transferis suspended.

[7325] Host to Client Addressing Mechanism

[7326] The address space of an FPGA co-processor is used to stream datato the function residing on the co-processor. Each function on theco-processor may have a unique address assigned to it. The designationof the addresses it at the designers discretion. The only address thatcannot be used for a function identifier is address zero. Address zerois reserved for system use.

[7327]FIG. 92 shows a typical address packet 9200. The most significant8 bits of an address is ignored by the client address decoders and usedas a command byte instead. The most significant 8 bits of an addresspacket are used as an address modifier. All other bits are available foruse as function indexes. See Table 3. TABLE 3 Value of Address MeaningModifier Interpretation of Data Address Zero Commands (used when readingfrom address zero) Set FIFO trigger level 1 Value for desired triggerlevel Query function status 2 Function address Set interrupt timeouttimer 3 Time in μs Address Zero Commands (used when reading from addresszero) Service required 1 Function address Function available 2 Functionaddress Function busy 3 Function address

[7328] Currently the address modifier is not used when using an addressvalue other than zero. When using an address value other than zero theaddress modifier should be set to zero.

[7329] Address Zero

[7330] Address zero is reserved for system use. This is the only addressthat cannot be used for a user function index.

[7331] Address Zero Functionality:

[7332] See Table 4. TABLE 4 Address Host Number Mode Description ofaddress usage 0 Read Read function status FIFO. The function status FIFOmay contain messages from functions to the host. A message is a singledouble word; 32 bits of data. The messages from the client should beinterpreted as an address packet using the status modifiers to interpretthe address modifier data. 0 Write The host can use the address modifierdata to send command to the client.

[7333] Arbitration in a Multiple Host Environment

[7334] Client Message Signal/Interrupt

[7335] The client has only one mechanism to signal to the host. This maybe in the form of an interrupt. The client may use this interrupt topass two different messages to a host. When a host receives theinterrupt it may query the client to determine the reason for theinterrupt.

[7336] The host queries the client by reading from address zero. Thismay read the client message FIFO. The data sent by the client may be inthe form of address packets with the client to host interpretation ofthe address modifier bit. The client may transmit zero valued addresspackets when there is no more data to read from the client message FIFO.Messages from the client may either be data ready messages fromfunctions or function available messages from the client.

[7337] Host API

[7338] The specification provides details about functional interfacesfor the components of the host API.

[7339] Physical Component Library

[7340] The physical component library is platform and protocoldependent. A basic outline for a physical library implementation may begiven here.

[7341] For a host to communicate with a client first requires that theclient is first made to listen to the communication. This may beimplemented by activating the co-processors chip select line or anotheralternative method. Once the co-processor is listening the host maytransfer an address. Once a host has transmitted an address it maytransfer data according to the host client interactions protocol.

[7342] Unique identifiers may be assigned to each function for progressmonitoring.

[7343] API Public Interface Library

[7344] Deadline Scheduling of Communication Requests

[7345] It is possible to have several active data transfers at one timeand it is possible to interrupt a transfer.

[7346] Client API

[7347] Physical Core and User Core Linkages

[7348] The co-processor construction libraries contain all the softwareneeded to construct the framework of a co-processor. MPRAMs to allowfast data transfer between the physical core and user core(s) whenrunning in different clock domains.

[7349] An exemplary floating and fixed point library will now be setforth along with information on waveform analysis.

Fixed and Floating Point Library

[7350] The Handel-C Floating Point Library provides floating-pointsupport to applications written with the Handel-C developmentenvironment.

[7351] Features of the Floating Point Library according to a preferredembodiment include the following:

[7352] Zero-cycle addition, multiplication and subtraction.

[7353] Contains useful operators such as negation, absolute values,shifts and rounding.

[7354] Supports numbers of up to exponent width 15 and mantissa width63.

[7355] Supports conversion to and from integers.

[7356] Provides square root functionality.

[7357] The Floating Point Library can be used to provide the followingapplications.

[7358] Floating precision DSP's.

[7359] Vector matrix computation.

[7360] ‘Real World’ applications.

[7361] Any computation requiring precision.

[7362] In the Library, variables are kept in structures whose widths aredefined at compile time. There are three parts to the structure; asingle sign bit, exponent bits whose width is user defined upondeclaration, and mantissa bits, also user defined. The ‘real’ value ofthe floating point number may be:

[7363] (−1)^(sign).2^((exponent-bas)). (1.mantissa)

[7364] Where the bias depends on the width of the exponent.

[7365] In use, floating point variable widths are set by usingdeclaration macros at compile time. illustrative declaration macros areset forth below.

[7366] The library is used by calling one of the zero cycle macroexpressions.

[7367] a=FloatAdd( b, c);

[7368] Multi-cycle macros are called in a different way.

[7369] FloatDiv( b, c, a);

[7370] The macros are not inherently shared; they are automaticallyexpanded where they are called. If extensive use of some of the macrosis required, it is advisable to share them in the following manner.

[7371] For zero-Cycle macros:

[7372] shared expr fmul_(—)1(a, b)=FloatMult(a, b);

[7373] shared expr fmul_(—)2(a, b)=FloatMult(a, b);

[7374] For multi-cycle macros.

[7375] void fdiv1( FLOAT_TYPE *d, FLOAT_TYPE *n,

[7376] FLOAT_TYPE *q)

[7377] {

[7378] FloatDiv(*d, *n, *q);

[7379] }

[7380] There will now be defined two zero-cycle multipliers and onedivider. All the usual precautions on shared hardware may now be taken.

[7381] The following table, Table 5, provide performance statistics forvarious illustrative embodiments.

[7382] Altera Flex 10K30A FPGA. TABLE 5 Float Size CLB Max Clock(exp/mant) Slices Speed FloatAdd 6/16 1205 9.46 FloatMult 6/16 996 9.38FloatDiv 6/16 390 22.02 FloatSqrt 6/16 361 18.21 FloatAdd 8/23 1328 6.53FloatMult 8/23 1922 7.05 FloatDiv 8/23 528 16.80 FloatSqrt 8/23 50513.47 Xilinx Virtex V1000-6 FPGA. FloatAdd 6/16 799 33.95 FloatMult 6/16445 30.67 FloatDiv 6/16 348 39.61 FloatSqrt 6/16 202 32.93 FloatAdd 8/231113 33.95 FloatMult 8/23 651 28.79 FloatDiv 8/23 459 36.72 FloatSqrt8/23 273 38.31

[7383] The program files that make up this Library and their purpose areset forth below. Filename Purpose Float.h Prototypes the macros to theuser Float.lib Stores the functionality of the library

[7384] Illustrative macros that may be defined in the Handel-C code arepresented in the following table. Macro Name Type Purpose FLOAT # defineSets the widths of a Floating- point variable FloatAbs Macro Returnsabsolute value of a Floating- expression point number FloatNeg MacroReturns negation of a Floating- expression point number FloatLeftShiftMacro Left shifts a Floating-point number expression FloatRightShiftMacro Right shifts a Floating-point number expression FloatRound MacroRounds the mantissa of a Floating- expression point number FloatConvertMacro Changes a Floating-point number's expression width FloatMult MacroMultiplies two Floating-point numbers expression together FloatAdd MacroAdds two Floating-point numbers expression together FloatSub MacroSubtracts two Floating-point numbers expression from each other FloatDivMacro Divides two Floating-point numbers procedure FloatSqrt Macro Findsthe square root of a Floating- procedure point number FloatToUInt MacroConverts a Floating-point number to expression an unsigned integerFloatToInt Macro Converts a Floating-point number to expression a signedinteger FloatFromUInt Macro Converts an unsigned integer to a expressionFloating-point number FloatFromlnt Macro Converts a signed integer to aexpression Floating-point number

[7385] Software Development for the Floating-Point Library

[7386] This section specifies in detail the performance and functionalspecification of the design. It also documents tests that can be used toverify that each macro functions correctly and that they integrate towork as one complete library.

[7387] The purpose of this design is to update an existing library toenable the user to perform arithmetic operations and integer to floatingpoint conversions on floating point numbers in Handel-C.

[7388] About the Macros

[7389] Representation of a Floating Point Number.

[7390] A floating-point number is represented as a structure in themacros. The structure has three binary sections as to the IEEE 754specifications.

[7391] Sign bit (unsigned int x.Sign)

[7392] Exponent (unsigned int x.Exponent)

[7393] Mantissa (unsigned int x.Mantissa)

[7394] In the library the structure of a floating-point number, say x,may be as follows:

[7395] x={x.Sign, x.Exponent, x.Mantissa}

[7396] This represents the number:

[7397] (−1)^(x.Sign)* (1.(x.Mantissa) )*2^((x.Exponent-bias))

[7398] This expression can represent any decimal number within a rangerestricted by the exponent and mantissa width. Below is an example ofhow a floating-point number is defined. #include <Float.h> set clock =external “P1”; typedef FLOAT(4,6)  Float_4_6; void main() { Float_4_6 x;x = { 0, 9, 38 }; }

[7399] First a structure type is chosen by stating the widths of theexponent and mantissa. The exponent is chosen to be of width 4 and themantissa to be of width 6. This structure is named Float_(—)4_(—)6 and xis defined to be of this type.

[7400] x.Sign=0

[7401] This means that the number is positive.

[7402] x.Exponent=9

[7403] x.Exponent is unsigned but represents a signed number. To do thisthe exponent needs a correcting bias which is dependent on it's width.

[7404] Bias=2^(( Width of exponent −1))−1

[7405] In this case as the exponent width is 4 then the bias is(2³−1)=7. The number 9 therefore means the multiplying factor is2⁽⁹⁻⁷⁾=2²=4.

[7406] x.Mantissa=38

[7407] The mantissa represents the decimal places of the number. Asx.Mantissa=38=100110 then this represents the binary number 1.100110 inthe equation. In decimal this is 1.59375. The one added to this numberis known as a hidden 1.

[7408] The floating point number represented by {0,9,38} is:

[7409] (−1)⁰(1.59375)(4)=6.375

[7410] IEEE Width Specifications.

[7411] The widths of the exponent and mantissa have certain setspecifications.

[7412] IEEE 754 Single Precision

[7413] Exponent is 8 bits and has a bias of 127

[7414] Mantissa is 23 bits not including the hidden 1.

[7415] IEEE 754 Double Precision

[7416] Exponent is 11 bits and has a bias of 1023

[7417] Mantissa is 52 bits not including the hidden 1.

[7418] IEEE 754 Extended Precision

[7419] Exponent is 15 bits and has a bias of 32767

[7420] Mantissa is 64 bits not including the hidden 1.

[7421] The precision types can be requested by specifying these Exponentand Mantissa widths for the floating point number.

[7422] Valid Floating-point Numbers.

[7423] For the purposes of this section a valid floating-point number isone of Exponent width less than 16 and Mantissa width less than 64. TheExponent and Mantissa are any bit pattern inside those widths whichincludes the special bit patterns. This library is tested up to thislevel.

[7424] Single Cycle Expressions.

[7425] Most of the library utilities are zero cycle macro expressionsand so use a single cycle when part of an assignment. They allow inputvariables of any width (up to a maximum mantissa width of 63). They mayhowever only be tested up to a precision which is 1 sign bit, 15exponent bits and 63 mantissa bits.

[7426] An example of a single cycle expression is the subtractionutility. This macro takes two floating-point numbers, f1 and f2 of thesame structure type.

[7427] result=FloatSub(f1, f2);

[7428] Result would then be a floating-point number with the samestructure type as f1 and f2.

[7429] Division and Square Root Macros.

[7430] The only utilities implemented as macro procedures (which are notsingle cycle expressions) are the division and square-root macros. Theseare called in a slightly different manner, with one of the inputparameters eventually holding the result value. For example, thedivision macro is defined as:

[7431] FloatDiv(N, D, Q);

[7432] The parameters for all these functions are:

[7433] N floating point numerator.

[7434] D floating point divisor.

[7435] Q floating point quotient (the result value).

[7436] N and D are unchanged after the macro is completed.

[7437] Special Values.

[7438] Special bit patterns are recognized in the library. These arereferred to as Not a Number (NaN) and infinity.

[7439] NaN

[7440] NaN is represented by all 1's in the exponent and any non-zeropattern in the mantissa. Following is an example of a single precisionNaN in binary.

[7441] x.Sign=0

[7442] x.Exponent=11111111

[7443] x.Mantissa=000000000000000000000001

[7444] Infinity

[7445] Infinity is represented by all 1's in the exponent and all 0's inthe mantissa. This is the only way the single precision infinity can berepresented in binary.

[7446] x.Sign=0

[7447] x.Exponent=11111111

[7448] x.Mantissa=00000000000000000000000

[7449] Output When Errors Occur.

[7450] When an error occurs in the calculation a special bit pattern isoutput as error messages. The bit pattern that is produced depends onthe situation. Several illustrative bit patterns are set forth below.Underflow is not strictly an error, but it is included below in Table 6for reference. TABLE 6 Problem Where problem number Problem occursOutput 1 Input Infinity Input Infinity 2 Overflow Result Infinity 3 x/0,x != 0 Input Infinity 4 Input NaN Input NaN (Mantissa: Same as input) 50 * Infinity Input NaN (Mantissa: 1) 6 0/0 Input NaN (Mantissa: 2) 7sqrt(x), x < 0 Input NaN (Mantissa: 3) 8 Infinity + (−Infinity) InputNaN (Mantissa: 4) 9 Infinity/Infinity Input NaN (Mantissa: 5) 10Underflow Result 0 11 sqrt(−0) Input −0

[7451] Macro Definitions.

[7452] For each of the following macros all input and resultfloating-point numbers have the same structure type.

[7453] Structure

[7454] ID: Structure 1

[7455] Prototype: #define FLOAT(ExpWidth, MantWidth) float_Name

[7456] Description.

[7457] Defines a structure called float_Name with an unsigned integerpart called Sign (of width 1), unsigned integer part called Exponent (ofwidth ExpWidth) and unsigned integer part called Mantissa (with widthMantWidth). Note Table 7. TABLE 7 Parameters Description Range ExpWidthThe width of the exponent (1 . . . 15) MantWidth The width of themantissa (1 . . . 63)

[7458] Absolute Value.

[7459] ID: Function 1

[7460] Prototype: FloatAbs(x)

[7461] Description.

[7462] Returns the absolute (positive) value of a floating point number.

[7463] Possible Error.

[7464] None. Note Table 8. TABLE 8 Parameters Description Range xFloating-point Number Any valid F.P. number

[7465] Negation.

[7466] ID: Function 2

[7467] Prototype: FloatNeg(x)

[7468] Description.

[7469] Returns the negated value of a floating point number.

[7470] Possible Error.

[7471] Negating zero returns a zero. Note Table 9. TABLE 9 ParametersDescription Range x Floating-point Number Any valid F. P. number

[7472] Left Shift.

[7473] ID: Function 3

[7474] Prototype: FloatLeftShift (X,V)

[7475] Description.

[7476] Shifts a floating-point number by v places to the left. Thismacro is equivalent to << for integers.

[7477] Possible Error.

[7478] 1, 2 & 4.

[7479] Example.

[7480] Single precision representation of 6 left shifted by 4.

[7481] (−1)⁰(1+0.5)*2⁽¹²⁹⁻¹²⁷⁾<<4=(−1)⁰(1+0.5)*2⁽¹³³⁻¹²⁷⁾

[7482] The result is the representation of 96 or 6*2⁴. Note Table 10.TABLE 10 Parameters Description Range x Floating-point Number Any validF. P. number v Amount to shift by. Unsigned integer (0 . . . width(x))

[7483] Right shift.

[7484] ID: Function 4

[7485] Prototype: FloatRightShift(x, v)

[7486] Description.

[7487] Shifts a floating-point number by v places to the right. Thismacro is equivalent to >> for integers.

[7488] Possible Error.

[7489] 1, 4 & 10. Note Table 11. TABLE 11 Parameters Description Range xFloating-point Number Any valid F. P. number v Amount to shift by.Unsigned integer (0 . . . width(x))

[7490] Nearest Rounding.

[7491] ID: Function 5

[7492] Prototype: FloatRound(x, MantWidth)

[7493] Description.

[7494] Rounds a floating-point number to have mantissa width Mantwidth.The value MantWidth may be less than the original mantissa width or elsethe macro won't compile.

[7495] Possible Errors.

[7496] 1 & 4. Note Table 12. TABLE 12 Parameters Description Range xFloating-point number Any valid F. P. number of any width MantWidthMantissa width of the result Unsigned integer (1 . . . 63)

[7497] Conversion Between Widths.

[7498] ID: Function 6

[7499] Prototype FloatConvert(x, ExpWidth, MantWidth)

[7500] Description.

[7501] Converts a floating-point number to a float of exponent widthExpWidth and mantissa width MantWidth.

[7502] Possible Errors.

[7503] 1, 2 & 4. Note Table 13. TABLE 13 Parameters Description Range xFloating-point number Any valid F. P. number of any width ExpWidthExponent width of the result Unsigned integer (1 . . . 15) MantWidthMantissa width of the result Unsigned integer (1 . . . 63)

[7504] Multiplier.

[7505] ID: Function 7

[7506] Prototype FloatMult(x1, x2)

[7507] Description.

[7508] Multiplies two floating point numbers of matching widths.

[7509] Possible Errors.

[7510] 1, 2, 4, 5 & 10. Note Table 14. TABLE 14 Parameters DescriptionRange x1, x2 Floating-point numbers Any valid F. P. number

[7511] Addition.

[7512] ID: Function 8

[7513] Prototype: FloatAdd(x1, x2)

[7514] Description.

[7515] Adds two floating point numbers of matching widths.

[7516] Possible Errors.

[7517] 1, 2, 4 & 8. Note Table 15. TABLE 15 Parameters Descnption Rangex1, x2 Floating-point numbers Any valid F. P. number

[7518] Subtraction.

[7519] ID: Function 9

[7520] Prototype: FloatSub(x1, x2)

[7521] Description.

[7522] Subtracts two floating-point numbers of matching widths (x1-x2).

[7523] Possible Errors.

[7524] 1, 2, 4 & 8. Table 16. TABLE 16 Parameters Description Range x1,x2 Floating-point numbers Any valid F. P. number

[7525] Division.

[7526] ID: Function 10

[7527] Prototype: FloatDiv( N, D, Q)

[7528] Description.

[7529] Divides two floating-point numbers of matching widths and outputsthe quotient. N/D=Q

[7530] Possible Errors.

[7531] 1, 2, 3, 4, 6, 9 & 10. TABLE 17 Parameters Description Range N, DInput floating-point numbers Any valid F. P. number Q Outputfloating-point Any valid F. P. number number = N/D

[7532] Square Root.

[7533] ID: Function 11

[7534] Prototype: Floatsqrt(R, Q)

[7535] Description.

[7536] Square roots a floating-point number. Sqrt(R)=Q

[7537] Possible Errors.

[7538] 1, 4, 7, 10 & 11. Table 18. TABLE 18 Parameters Description RangeR Input floating-point number Any valid F. P. number Q Outputfloating-point number = Any valid F. P. Sqrt(R) number

[7539] Floating Point to Unsigned Integer Conversion.

[7540] ID: Function 12

[7541] Prototype: FloatToUInt(x, wi)

[7542] Description.

[7543] Converts a floating-point number into an unsigned integer ofwidth wi using truncation rounding. If the number is negative a zero isreturned.

[7544] Possible Errors.

[7545] 1 & 4. Table 19. TABLE 19 Parameters Description Range xFloating-point number Any valid F. P. number wi Total width of theresult Any unsigned integer

[7546] Floating Point to Signed Integer Conversion.

[7547] ID: Function 13

[7548] Prototype: FloatToInt(x, wi)

[7549] Description.

[7550] Converts a floating point number into a signed integer of widthwi using truncation rounding.

[7551] Possible Errors.

[7552] 1 & 4. TABLE 20 Parameters Description Range x Floating-pointnumber Any valid F. P. number wi Total width of the result Any signedinteger

[7553] Unsigned Integer to Floating Point Conversion.

[7554] ID: Function 14

[7555] Prototype: FloatFromUInt(u, ExpWidth, MantWidth)

[7556] Description.

[7557] Converts an unsigned integer into a floating point number ofexponent width ExpWidth and mantissa width MantWidth using truncationrounding.

[7558] Possible Errors.

[7559] 2. See Table 21. TABLE 21 Parameters Description Range u Unsignedinteger Any unsigned integer ExpWidth Exponent width of the resultUnsigned integer (1 . . . 63) MantWidth Mantissa width of the resultUnsigned integer (1 . . . 15)

[7560] Signed Integer to Floating Point Conversion.

[7561] ID: Function 15

[7562] Prototype: FloatFromInt(i, ExpWidth, MantWidth)

[7563] Description.

[7564] Converts a signed integer into a floating point number ofexponent width ExpWidth and mantissa width MantWidth using truncationrounding.

[7565] Possible Errors.

[7566] 2. Note Table 22. TABLE 22 Parameters Description Range i IntegerAny integer ExpWidth Exponent width of the result Unsigned integer (1 .. . 63) MantWidth Mantissa width of the result Unsigned integer (1 . . .15)

[7567] Detailed Design

[7568] The following subsections describe design specifications forpracticing various embodiments of the present invention.

[7569] Interface Design

[7570] Structure 1—FLOAT(ExpWidth, MantWidth) Float Name

[7571] Description.

[7572] Defines a structure called Float_Name with an unsigned integerpart called Sign (of width 1), an unsigned integer part called Exponent(of width ExpWidth) and an unsigned integer part called Mantissa (withwidth MantWidth).

[7573] Valid Floating-point Numbers.

[7574] For the purposes of this section, a valid floating-point numberis one of ExpWidth less than 16 and MantWidth less than 65. The Exponentand Mantissa are any bit pattern inside those widths including thespecial bit patterns. The library may be tested up to this level.

[7575] Input.

[7576] ExpWidth—The width of the exponent.

[7577] MantWidth—The width of the mantissa.

[7578] Output.

[7579] Format of the structure: struct { unsigned int 1 Sign; unsignedint ExpWidth Exponent; unsigned int MantWidth Mantissa; } float_Name;

[7580] Component Detail Design

[7581] Explanation of the Detailed Description.

[7582] If a variable isn't mentioned then it is the same on output asinput. For ease of understanding, the operations on each component haveeach been provided with a header.

[7583] Each macro tests if the input is infinity or NaN before it doesthe stated calculations. If the input is invalid the same floating-pointnumber is output. This can be done by: if Exponent = −1 { x = x } else {x = Calculation }

[7584] Some of the library macros call upon other macros unseen by theuser. These are listed in each section along with a brief description asto their use under the title “Dependencies”.

[7585] Function 1—FloatAbs(x)

[7586] Description.

[7587] Returns the absolute (positive) value of a floating point number.

[7588] Input.

[7589] x—Floating point number of width up to {1, 15, 63}.

[7590] Output.

[7591] Floating point number of same width as input.

[7592] Detailed Description.

[7593] Sign

[7594] x.Sign=0.

[7595] Function 2—FloatNeg(x)

[7596] Description.

[7597] Returns the negated value of a floating point number.

[7598] Input.

[7599] x—Floating point number of width up to {1, 15, 63}.

[7600] Output.

[7601] Floating point number of same width as input.

[7602] Detailed Description.

[7603] Sign

[7604] if Exponent@Mantissa=0.

[7605] {

[7606] x.Sign=0, Exponent 0, Mantissa=0

[7607] }

[7608] else

[7609] {

[7610] x.Sign=!Sign

[7611] }

[7612] Function 3—FloatLeftShift(x, v)

[7613] Description.

[7614] Shifts a floating-point number by v places to the left. Thismacro is equivalent to << for integers.

[7615] Input.

[7616] x—Floating point number of width up to {1, 15, 63}.

[7617] v—Unsigned integer to shift by. This is not larger than ExpWidth.

[7618] Output.

[7619] Floating point number of same width as input.

[7620] Detailed Description. if Exponent + v > The maximum exponent forthe width { x = infinity } else { Exponent if x = 0 { x = x } else {x.Exponent = Exponent + v } }

[7621] Function 4—FloatRightShift(x, v)

[7622] Description.

[7623] Shifts a floating-point number by v places to the right. Thismacro is equivalent to >> for integers.

[7624] Input.

[7625] x—Floating point number of width up to {1, 15, 63}.

[7626] v—Unsigned integer to shift by. This is not larger than ExpWidth.

[7627] Output.

[7628] Floating point number of same width as input.

[7629] Detailed Description. if Exponent − v < The minimum Exponent forthe width { x = 0 } else { Exponent if x = 0 { x = x } else { x.Exponent= Exponent − v } }

[7630] Function 5 FloatRound(x, MantWidth)

[7631] Description.

[7632] Rounds a floating-point number to one with mantissa widthMantWidth.

[7633] Input.

[7634] x—Floating point number of width up to {1, 15, 63}.

[7635] MantWidth—Round to unsigned mantissa width MantWidth.

[7636] Output.

[7637] Floating point number of same exponent width as input andmantissa width MantWidth.

[7638] Dependencies.

[7639] RoundUMant—extracts mantissa as an unsigned integer (with hidden1)

[7640] RoundRndMant—Rounds mantissa to MantWidth +2

[7641] Detailed Description.

[7642] Mantissa if the next least significant bit and any of the otherless significant bits after the cut off point are 1 { x.Mantissa = TheMantWidth most significant bits of Mantissa + 1 } else { x.Mantissa =The MantWidth most significant bits of Mantissa } Exponent if Mantissaoverflows during rounding {  x.Exponent = Exponent + 1 } else { x.Exponent = Exponent }

[7643] Function 6—FloatConvert(x, ExpWidth, MantWidth)

[7644] Description.

[7645] Converts a floating-point number to a float of exponent widthExpWidth and mantissa width MantWidth.

[7646] Input.

[7647] x—Floating point number of width up to {1, 15, 63}.

[7648] ExpWidth—Convert to unsigned exponent width ExpWidth.

[7649] MantWidth—Convert to unsigned mantissa width MantWidth.

[7650] Output.

[7651] Floating point number of exponent width ExpWidth and mantissawidth MantWidth.

[7652] Detailed Description. if (Exponent − old bias) > new bias { x =infinity } else { Exponent x.Exponent = Exponent − old bias + new biasMantissa if new width is greater than old width { x.Mantissa = Extendedmantissa } else { x.Mantissa = Most significant width bits } }

[7653] Function 7—FloatMult(x1, x2)

[7654] Description.

[7655] Multiplies two floating point numbers.

[7656] Input.

[7657] x1, x2—Floating point numbers of width up to {1, 15, 63}

[7658] Output.

[7659] Floating point number of same width as input.

[7660] Dependencies.

[7661] MultUnderflowTest—Tests exponent for underflow.

[7662] MultOverflowTest—Tests exponent for overflow.

[7663] MultSign—Multiplies the Signs.

[7664] GetDoubleMantissa—Pads the Mantissa with mantissa width zeros.

[7665] MantissaMultOverflow—Tests mantissa for overflow.

[7666] AddExponents—Adds exponents.

[7667] MultMantissa—Multiplies mantissa and selects the right bits.

[7668] Detailed Description. Test for exponent underflow if underflow istrue { x = 0 } else {  Test for exponent overflow if overflow is true {x = Infinity } else { Sign x.Sign = x1.Sign or x2.Sign Exponent ifmantissa overflows { x.Exponent = x1.Exponent + x2.Exponent + 1 } else {x.Exponent = x1.Exponent + x2.Exponent } Mantissa Both mantissas arepadded below with zeros Mantissa = x1.Mantissa * x2.Mantissa x.Mantissa= top input width mantissa bits } }

[7669] Function 8—FloatAdd(X1, X2)

[7670] Description.

[7671] Adds two floating point numbers.

[7672] Input.

[7673] x1, x2—Floating point numbers of width up to {1, 15, 63}.

[7674] Output.

[7675] Floating point number of same width as input.

[7676] Dependencies.

[7677] SignedMant—Extracts mantissa as a signed integer.

[7678] MaxBiasedExp—determines the greater of two biased exponents.

[7679] BiasedExpDiff—Gets the difference between two exponents (to 64).

[7680] AddMant—Adds two mantissa.

[7681] GetBiasedExp—Gets biased exponent of the result.

[7682] GetAddMant—Gets the normalised mantissa of the result.

[7683] Detailed Description. Test for overflow  if number overflows { x= infinity }  else  { Sign Adjust the mantissa to have same exponent Addthem x.Sign = Sign of the result Exponent if addition = 0 { x.Exponent =0 } else { x.Exponent = Max Exponent − Amount Mantissa adjusted by }Mantissa  Adjust mantissa to have the same exponent  Mantissa =x1.Mantissa  +x2.Mantissa  x.Mantissa = top width bits of mantissa }

[7684] Function 9—FloatSub(x1, x2)

[7685] Description.

[7686] Subtracts one float from another.

[7687] Input.

[7688] x1, x2—Floating point numbers of width up to {1, 15, 63}.

[7689] Output.

[7690] Floating point number (x1-x2) of same width as input.

[7691] Dependencies.

[7692] FloatNeg—Negates number.

[7693] FloatAdd—Adds two numbers.

[7694] Detailed Description.

[7695] x=FloatAdd(x1, −x2)

[7696] Function 10—FloatDiv(N, D, Q)

[7697] Description.

[7698] Divides two floats and outputs the quotient. Q=N/D.

[7699] Input.

[7700] N, D, Q—Floating point numbers of width up to {1, 15, 63}

[7701] Output.

[7702] None as it is a macro procedure.

[7703] Detailed Description.

[7704] This division macro is based on the non-restoring basic divisionscheme for signed numbers. This scheme has the following routine:

[7705] Set s=2 * (1 concatenated to N.Mantissa)

[7706] Set d=2 * (1 concatenated to D.mantissa)

[7707] Check to see if s is larger than d

[7708] If so set exponent adjust to zero

[7709] Else s=s/2 and set exponent adjust to one

[7710] Then do the following procedure mantissa width+1 times

[7711] Check to see if first digit of (2 * s)−d is 0

[7712] If so s=(2* s)−d, q=(2 * q)+1

[7713] Else s=2* s, q=2 * q

[7714] The quotient Q is then

[7715] Q.Sign=N.Sign or D.Sign

[7716] Q.Exponent=N.Exponent−D.Exponent+the exponent adjust−1

[7717] Q.Mantissa=The least significant mantissa width bits of q

[7718] Worked example—dividing 10 by −2.

[7719] 10=(1.25)*2^ 3={0, 0011, 01000}

[7720] −2=(1.0)*2^ 1={1, 0001, 00000}

[7721] So

[7722] s=01010000

[7723] d=01000000

[7724] Is s larger than d? Yes so

[7725] s=00101000

[7726] adj_e=1

[7727] Iteration 1.

[7728] (2 * s)−d=01010000−01000000=00010000

[7729] The first digit is 0 so

[7730] s=00010000

[7731] q=1

[7732] Iteration 2.

[7733] (2 * s)−d=00100000−01000000=10100000

[7734] The first digit is 1 so

[7735] s=00100000

[7736] q=10

[7737] Iteration 3.

[7738] (2 * s)−d=01000000−01000000=00000000

[7739] The first digit is 0 so

[7740] s=00000000

[7741] q=101

[7742] Iteration 4.

[7743] (2 * s)−d=00000000−01000000=11000000

[7744] The first digit is 1 so

[7745] s=00000000

[7746] q=1010

[7747] Iteration 5.

[7748] (2 * s)−d=000000−0100000=11000000

[7749] The first digit is 1 so

[7750] s=00000000

[7751] q=10100

[7752] The result is that q ends up as 10100000 after iteration 8.

[7753] The quotient Q is then:

[7754] Q.Sign=0 or 1=1

[7755] Q.Exponent=N.Exponent−D.Exponent+adj_e−1=3−1+1−1=2

[7756] Q.Mantissa=01000

[7757] So Q is −5 as required. if D = 0 { Sign = D Sign Exponent = −1Mantissa = 1 } else { if N Exponent = −1 { Q = N } else { if D Exponent= −1 { Q = D } else { if N = 0 { s = 0 } else { s = ( 1 @ N Mantissa<< 1) } d = (1 @ N Mantissa << 1) q = 0 i = 0 if most significant bit(s−d) == 0 { S = S >> 1 adj = 1 } else { adj = 0 } while i not equal towidth of mantissa + 1 { if most significant bit of (s << 1) − d = 0 { s= (s << 1 ) − d q = (q << 1) + 1 } else { s = s << 1 q = q << 1 } } i =i + 1 Q Sign = N Sign or D Sign if q = 0 { Q Exponent = 0 } else { QExponent = N Exponent − D Exponent + adj + Bias − 1 } Q Mantissa =bottom width bits of q } } }

[7758] Function 11—Floatsqrt(R, Q)

[7759] Description.

[7760] Calculates the square root of the input. Q=Sqrt(R)

[7761] Input.

[7762] R, Q—Floating point numbers of width up to {1, 15, 63}.

[7763] Output.

[7764] None as it is a macro procedure.

[7765] Dependencies.

[7766] GetUnbiasedExp—Extracts unbiased exponent.

[7767] Detailed Description.

[7768] This square root macro is based on the restoring shift/subtractalgorithm. This scheme has the following routine:

[7769] Set q=1

[7770] Set i=0

[7771] Check to see if exponent positive

[7772] If so

[7773] set e=R.Exponent/2

[7774] Set s=R.Mantissa

[7775] Else

[7776] Set e=R.Exponent−1

[7777] Set=2 * R.Mantissa+2^ (mantissa width)

[7778] Then do the following procedure mantissa width+1 times.

[7779] Check to see if first digit of (2 * s)−(4*q+1)*2^ (Mantissawidth−1−i) is 0

[7780] If so s=(2 * s)−(4* q+1)*2^ (Mantissa width−1−i), q=(2 * q)+1

[7781] Else s=2 * s, q=2 * q

[7782] The square root Q is then

[7783] Q.Sign=0

[7784] Q.Exponent=e+bias

[7785] Q.Mantissa=The least significant mantissa width bits of q

[7786] Worked example−Square rooting 36

[7787] 36=(1.125)*2^ 5={0, 0101, 00100}

[7788] So as exponent is odd

[7789] e=0010

[7790] s=2 * mantissa+2^ 5=00001000+00100000=00101000

[7791] q=1

[7792] Iteration 1.

[7793] 01010000−(00000100+00000001)<<4=00000000

[7794] First digit is 0 so

[7795] s=00000000

[7796] q=11

[7797] Iteration 2.

[7798] 00000000−(00001100−00000001)<<3=10011000

[7799] First digit is 1 so

[7800] s=00000000

[7801] q=110

[7802] Iteration 3.

[7803] 00000000−(00011000−00000001)<<2=10011100

[7804] First digit is 1 so

[7805] s=00000000

[7806] q=1100

[7807] This continues until we have the answer

[7808] Q.Sign=0

[7809] Q.Exponent=2+bias (in this case bias is 7)

[7810] Q.Mantissa=10000

[7811] So Q is the integer 6. if R Sign = 1 { Q Sign = R Sign Q Exponent= −1 Q Mantissa = 2 } else { if R Exponent = −1 { Q = R } else { ifunbiased exponent even { e =(Unbiased exponent)/2 s = R Mantissa } else{ e = (Unbiased exponent − 1)/2 s = ( R Mantissa << 1 ) + e {circumflexover ( +0 ♭+0 width of Q)} } q = 1 i = 0 while i not equal to widthMantissa + 1 { c = ((s << 1) − ((4*q + 1) << width mantissa − 1 − i) )if most significant bit of c = 1 { s = c q = ( q << 1 ) + 1 } else { s =s << 1 q = q << 1 } i = i + 1 } if R not equal to 0 { Q Sign = 0 QExponent = e + bias Q Mantissa = top width bits of q } else { Q = 0 } }}

[7812] Function 12—FloatToUInt(x, wi)

[7813] Description.

[7814] Converts a floating-point number into an unsigned integer ofwidth wi using truncation rounding. If the number is negative a zero isreturned.

[7815] Input.

[7816] x—Floating point number of width up to {1, 15, 63}

[7817] wi—unsigned width of unsigned integer

[7818] Output.

[7819] Unsigned integer of width wi.

[7820] Dependencies.

[7821] GetMant—Gets mantissa for conversion to integer

[7822] ToRoundInt—Rounds to nearest integer

[7823] MantissaToInt—Converts mantissa to integer

[7824] Detailed Description. if absolute value of float less than 0.5 orequal to 0 { Output 0  } else { Left shift mantissa by exponent placesRound to nearest integer Output (unsigned) integer }

[7825] Function 13—FloatToInt(x, wi)

[7826] Description.

[7827] Converts a floating point number into a signed integer of widthwi using truncation rounding.

[7828] Input.

[7829] x—floating point number

[7830] wi—unsigned width of integer

[7831] Output.

[7832] Signed integer of width wi.

[7833] Dependencies.

[7834] GetMant—Gets mantissa for conversion to integer.

[7835] ToRoundInt—Rounds to nearest integer.

[7836] MantissaToInt—Converts mantissa to integer.

[7837] Detailed Description. if absolute value of float less than 0.5 orequal to 0 { Output 0 } else { Left shift mantissa by exponent placesRound to nearest integer if sign = 0 {  Output integer } else {Output -integer } }

[7838] Function 14—FloatFromUInt(U, ExpWidth, MantWidth)

[7839] Description.

[7840] Converts an unsigned integer into a floating point number ofexponent width ExpWidth and mantissa width MantWidth using truncationrounding.

[7841] Input.

[7842] u—unsigned integer

[7843] ExpWidth—unsigned width of output exponent

[7844] MantWidth—unsigned width of output mantissa

[7845] Output.

[7846] Floating point number of exponent width ExpWidth and mantissawidth MantWidth.

[7847] Dependencies.

[7848] UIntToFloatExp—Gets signed integer to exponent

[7849] UIntToFloatNormalised—Gets signed integer to mantissa

[7850] Detailed Description. When finding the left most bit of u theleast significant bit is labeled 0 and the label numbering increases asthe bits become more significant. Sign Sign = most significant binaryinteger bit Exponent if integer = 0 { Exponent = 0 } else { Exponent =position of left most bit+ bias } Mantissa if integer = 0 {  Mantissa =0 } else }  if width integer < width mantissa { Mantissa = integer << (width mant − position of left most bit of u) } else }  Mantissa =integer << ( width integer− position of left  most bit of u) } }

[7851] Function 15—FloatFromInt(i, ExpWidth, MantWidth)

[7852] Description.

[7853] Converts a signed integer into a floating point number ofexponent width ExpWidth and mantissa width MantWidth using truncationrounding.

[7854] Input.

[7855] i—signed integer.

[7856] ExpWidth—unsigned width of output exponent

[7857] MantWidth—unsigned width of output mantissa

[7858] Output.

[7859] Floating point number of exponent width ExpWidth and mantissawidth MantWidth.

[7860] Dependencies.

[7861] IntToFloatExp—Gets unsigned integer to exponent

[7862] FltToFloatNormalised—Gets unsigned integer to mantissa

[7863] Detailed Description. When finding the left most bit of u theleast significant bit is labelled 0 and the label numbering increases asthe bits become more significant. Sign Sign = most significant integerbit Exponent if integer = 0 { Exponent = 0 } else { Exponent = positionof left most bit+ bias } Mantissa integer = absolute value of integer ifinteger = 0 {  Mantissa = 0 } else { if width integer < width mantissa {Mantissa = integer << (width mant − left most bit of integer ) } else {Mantissa = integer << (width integer − left most bit of integer) } }

[7864] Verification

[7865] Testing method can be implemented with verification methods suchas Positive (Pos), Negative (Neg), Volume and Stress (Vol), Comparison(Comp) and Demonstration (Demo) tests.

[7866] Positive Testing

[7867] Valid floating point numbers are entered into the macro and theresult is compared to the correct answer.

[7868] Negative Testing

[7869] Invalid floating point numbers are entered into the macro and theresultant error is compared to the correct error.

[7870] Volume and Stress Testing

[7871] Valid floating point numbers are repeatedly entered into themacro to see that it works in a correct and repeatable manner.

[7872] Comparison Testing

[7873] Correct results are gained from a reliable source to compare themacro results to.

[7874] Demonstration Testing

[7875] Behavior in representative circumstances is evaluated.

Fixed Point Library

[7876] Software Development for the Fixed-Point Library

[7877] This section specifics in detail the performance and functionalspecification of the Fixed-Point Library design. It describes howrequirements for implementation of the library are to be met. It alsodocuments tests that are useful for verifying that each Handel-C and/orsoftware unit functions correctly and that they integrate to work as onecomplete application.

[7878] The Handel-C Fixed-point Library contains a number of functionsfor the creation and manipulation of fixed-point numbers. It consists ofa library (lib) file, a header (.h) file and a function manual. Theheader prototypes the expressions available in the library.

[7879] The Handel-C Fixed-point Library is constrained to adopt thedesign philosophy of Handel-C where numerical operators require matchingtypes. Therefore the parameters of each function are of matching widthand type and the result returned may be of matching width and typeunless otherwise specified.

[7880] Number Structure

[7881] FIXED_SIGNED(int Width, frac Width)

[7882] This creates a structure to hold a signed fixed-point number.intWidth sets the number of integer bits and fracWidth sets the numberof fraction bits.

[7883] FIXED_UNSIGNED(intWidth,fracWidth)

[7884] This creates a structure to hold an unsigned fixed-point number.intWidth sets the number of integer bits and fracWidth sets the numberof fraction bits.

[7885] FIXED_ISSIGNED

[7886] Defined to equal 1.

[7887] FIXED_ISUNSIGNED

[7888] Defined to equal 0.

[7889] Bit Manipulation Operators

[7890] FixedLeftShift (fixed_Name, variable_Shift)

[7891] Returnsfixed_Name shifted left by variable_Shift number of bits.This produces a fixed-point number of the same type and width asfixed_Name with any bits shifted outside of its width being lost and anybits added being zero.

[7892] FixedRightShift(fixed_Name, variable_Shift)

[7893] Returnsfixed_Name shifted right by variable_Shift number of bits.This produces a fixed-point number of the same type as fixed_Name withany bits shifted outside of its width being lost. When shifting unsignedvalues the upper bits are padded with zeros. When shifting signedvalues, the upper bits are copies of the top bit of the original value.So signed numbers are sign extended in the same way as the Handel-Cshift right function.

[7894] Arithmetic Operators

[7895] Any attempt to perform one of these operations on two expressionsof differing widths or types may result in a compiler error.

[7896] FixedNeg(fixed_Name)

[7897] Returns the negative of the operand.

[7898] FixedAdd(fixed_Name1, fixed_Name2)

[7899] Returns the sum of the operands.

[7900] FixedSub(fixed_Name1, fixed_Name2)

[7901] Returns fixed_Name2 subtracted from fixed_Name1.

[7902] FixedMultSigned(fixed_Name1, fixed_Name2)

[7903] Returns the product of the operands for signed numbers only.

[7904] FixedMultUnsigned(fixed_Name1, fixed_Name2)

[7905] Returns the product of the operands for unsigned numbers only.

[7906] FixedDivSigned(fixed_Name1, fixed_Name2)

[7907] Returns fixed_Name1 divided by fired_Name2 for signed numbersonly.

[7908] FixedDivUnsigned(fixed_Name1, fixed_Name2)

[7909] Returns fixed_Name1 divided by fixed_Name2 for unsigned numbersonly.

[7910] FixedAbs(fixed_Name)

[7911] Returns the absolute value.

[7912] Relational Operators

[7913] These operators compare values of the same width and return asingle bit wide unsigned int

[7914] value of 0 for false or 1 for true.

[7915] FixedEq(fixed_Name1, fixed_Name2)

[7916] Returns true if the operands are equal.

[7917] FixedNEq(fixed_Name1, fixed_Name2)

[7918] Returns true if the operands are not equal.

[7919] FixedLT(fixed_Name1, fixed_Name2)

[7920] Returns true if fixed_Name1 is less than fixed_Name2.

[7921] FixedLTE(fixed_Name1, fixed_Name2)

[7922] Returns true if fixed_Name1 is less than or equal to fixed_Name2.

[7923] FixedGT(fixed_Name1, fixed_Name2)

[7924] Returns true if fixed_Name1 is greater than fixed_Name2.

[7925] FixedGTE(fixed_Name1, fixed_Name2)

[7926] Returns true if fixed_Name1 is greater than or equal tofixed_Name2.

[7927] Bitwise Logical Operators

[7928] These operators perform bitwise logical operations on fixed-pointnumbers. Both operands may be of the same type and width: the resultingvalue may also be this type and width.

[7929] FixedNot(fixed_Name)

[7930] Returns bitwise not.

[7931] FixedAnd(fixed_Name1, fixed_Name2)

[7932] Returns bitwise and.

[7933] FixedOr(fixed_Name1, fixed_Name2)

[7934] Returns bitwise or.

[7935] FixedXor(fixed_Name1, fixed_Name2)

[7936] Returns bitwise exclusive or.

[7937] Conversion Operators

[7938] These operators are for the type conversion of fixed numbers.

[7939] FixedIntWidth(fixed_Name)

[7940] Returns the width of the integer part of fixed_Name as a compiletime constant.

[7941] FixedFracWidth(fixed_Name)

[7942] Returns the width of the fraction part of fixed_Name as a compiletime constant.

[7943] FixedLiteral(isSigned, intWidth, fracWidth, intBits, fracBits)

[7944] Returns a signed fixed-point number if isSigned is true and anunsigned fixed-point number if isSigned is false. This number has aninteger part intBits of width intWidth and a fraction part fracBits ofwidthfracWidth.

[7945] FixedToInt(fixed_Name)

[7946] Returns the integer part of the fixed-point number with the sametype and width.

[7947] FixedToBool (fixed_Name)

[7948] Returns a single bit wide unsigned int value which is 0 for falseif the operand equals 0 and 1 for true otherwise.

[7949] FixedToBits(fixed_Name)

[7950] Returns the integer and fraction bits of fixed_Name concatenatedtogether. For a signed fixed-point number this may produce a signedinteger of width intWidth+fracWidth. For an unsigned fixed-point numberthis may produce an unsigned integer of width intWidth+fracWidth.

[7951] FixedCastSigned (isSigned, intWidth, fracWidth, fixed_Name)

[7952] Casts any signed fixed-point number to the type and widthspecified.

[7953] FixedCastUnsigned (isSigned, intWidth, fracWidth, fixed_Name)

[7954] Casts any unsigned fixed-point number to the type and widthspecified.

[7955] Design

[7956] This section may describe the present invention according to apreferred embodiment.

[7957] Interface

[7958] This library can be accessed via a standard header file includedin the client's programs by “#include <fixed.h>”.

[7959] Shared Resources

[7960] Although the internal macros may be used by more than one publicmacro there can be no sharing conflicts as they are not defined asshared expressions and as such Handel-C may generate all the hardwarerequired for every expression in the library every time it is used.

[7961] Note:

[7962] Handel-C arithmetic is used throughout the macros. This meansthat all operators return results of the same width as their operandsand all overflow bits are dropped. For example: #include “fixed.h” setclock = external “P1”; typedef FIXED_UNSIGNED(4,4) MyFixed; voidmain(void) { MyFixed fixed1, fixed2, fixed3; // Assign the value 5 tofixed1 fixed1 = FixedLiteral(FIXED_ISUNSIGNED, 4, 4, 5, 0); // Assignthe value 5.5 to fixed2 fixed2 = FixedLiteral(FIXED_ISSIGNED, 4, 4, 5,8); // Multiply the numbers together fixed3 = FixedMultUnsigned(fixed1,fixed2); }

[7963] This example results in fixed3 being set to 11.5:

[7964] fixed3.FixedIntBits=11;

[7965] fixed3.FixedFracBits=8;

[7966] The user is responsible for handling overflows explicitly and canuse FixedCastSigned and FixedCastUnsigned to change the width of afixed-point number.

[7967] Number Structure

[7968] The Handel-C data types used are signed and unsigned fixed-pointnumbers of user defined widths. The structures of the signed andunsigned fixed-point numbers are below. The widths of these fixed-pointnumbers are declared by the user. All the operations necessary to set,manipulate and extract the values of fixed_Name.FixedIntBits andfixed_Name.FixedFracBits are available in the library.

[7969] COMP 1.1 FIXED_SIGNED(intPVidth,fracWidth)

[7970] Description

[7971] This creates a structure to hold a signed fixed-point number.intWidth sets the number of integer bits and frac Width sets the numberof fraction bits.

[7972] Inputs

[7973] intWidth width of the integer part of the number

[7974] fracWidth width of the fraction part of the number

[7975] Output

[7976] Format of the structure:

[7977] struct

[7978] {

[7979] signed intWidth FixedIntBits;

[7980] signedfracWidth FixedFracBits;

[7981] }

[7982] COMP 1.2 FIXED_UNSIGNED(int Width,frac Width)

[7983] Description

[7984] This creates a structure to hold an unsigned fixed-point number.intWidth sets the number of integer bits and fracWidth sets the numberof fraction bits.

[7985] Inputs

[7986] intWidth width of the integer part of the number

[7987] fracWidth width of the fraction part of the number

[7988] Output

[7989] Format of the structure:

[7990] struct

[7991] {

[7992] unsigned intWidth FixedIntBits;

[7993] unsignedfrac Width FixedFracBits;

[7994] }

[7995] COMP 1.3 FIXED_ISSIGNED

[7996] Description

[7997] Defined to equal 1.

[7998] Inputs

[7999] None

[8000] Output

[8001] None

[8002] COMP 1.3 FIXED_ISUNSIGNED

[8003] Description

[8004] Defined to equal 0.

[8005] Inputs

[8006] None

[8007] Output

[8008] None

[8009] Bit Manipulation Operators

[8010] COMP 2.1 FixedLeftShift (fixed_Name, variable_Shift)

[8011] Description

[8012] Returns fixed_Name shifted left by variable Shift number of bits.This produces a fixed-point number of the same type and width asfixed_Name with any bits shifted outside of its width being lost andlower bits padded with zeros.

[8013] Inputs

[8014] fixed_Name Fixed-point number of any type or width

[8015] variable_Shift Unsigned integer number of bits to shift by. Widthset by:

[8016] width(variable_Shift)=log2ceil(fracWidth+intWidth+1)

[8017] Output

[8018] Fixed-point number of same type and width as fixed_Name

[8019] Detailed Description

[8020] Concatenate integer and fraction parts from fixed_Name into asingle bit string

[8021] Shift_Name left by int_value number of bits

[8022] Split result into integer and fraction parts of same type andwidth as fixed_Name

[8023] Return as struct

[8024] COMP 2.2 FixedRightShift(fixed_Name, variable_Shift)

[8025] Description

[8026] Returns fixed_Name shifted right by variable_Shift number ofbits. This produces a fixed-point number of the same type as fixed_Namewith any bits shifted outside of its width being lost. When shiftingunsigned values the upper bits are padded with zeros. When shiftingsigned values, the upper bits arc copies of the top bit of the originalvalue. So signed numbers are sign extended in the same way as theHandel-C shift right function.

[8027] Inputs

[8028] fixed_Name Fixed-point number of any type or width

[8029] variable_Shift Unsigned integer number of bits to shift by. Widthset by:

[8030] width(variable_Shift)=log2ceil(fracWidth+intWidth+1)

[8031] Output

[8032] Fixed-point number of same type and width as fixed_Name

[8033] Detailed Description

[8034] Concatenate integer and fraction parts from fixed_Name into asingle bit string

[8035] Shift fixed_Name right by int_value number of bits

[8036] Split result into integer and fraction parts of same type andwidth as fixed_Name

[8037] Return as struct

[8038] Arithmetic Operators

[8039] COMP 3.1 FixedNeg(fixed_Name)

[8040] Description

[8041] Returns the negative of fixed_Name. The result of using thismacro on an unsigned fixed-point structure is undefined.

[8042] Inputs

[8043] fixed_Name Fixed-point number of any type and width

[8044] Output

[8045] Fixed-point number of same type and width as fixed_Name

[8046] Detailed Description

[8047] Concatenate integer and fraction parts from fixed_Name into asingle bit string

[8048] Negate the bit string

[8049] Split result into integer and fraction parts of same type andwidth as fixed_Name

[8050] Return as struct

[8051] COMP 3.2 FixedAdd(fixed_Name1, fixed_Name2)

[8052] Description

[8053] Returns the fixed_Name1 and fixed_Name2 added together. Thenumber returned is of the same width as the operands so any bitsproduced by the addition outside of this width overflow and are dropped.

[8054] Inputs

[8055] fixed_Name1 Fixed-point number of any type or width

[8056] fixed_Name2 Fixed-point number of the same type and width

[8057] Output

[8058] Fixed-point number of same type and width as fixed_Name1

[8059] Detailed Description

[8060] At compile time check the operands are of the same width and ifnot give an assertion error

[8061] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8062] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8063] Add the bit strings and drop any overflow bits

[8064] Split result into integer and fraction parts of same type andwidth as fixed_Name1

[8065] Return as struct

[8066] COMP 3.3 FixedSub(fixed_Name1, fixed_Name2)

[8067] Description

[8068] Returns fixed_Name2 subtracted from fixed_Name1. The numberreturned is of the same width as the operands so any bits produced bythe subtraction outside of this width overflow and are lost.

[8069] Inputs

[8070] fixed_Name1 Fixed-point number of any type or width

[8071] fixed_Name2 Fixed-point number of the same type and width

[8072] Output

[8073] Fixed-point number of same type and width as fixed_Name1

[8074] Detailed Description

[8075] At compile time check the operands are of the same width and ifnot give an assertion error

[8076] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8077] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8078] Subtract the bit strings and drop any overflow bits

[8079] Split result into integer and fraction parts of same type andwidth as fixed_Name1

[8080] Return as struct

[8081] COMP 3.4 FixedMultSigned(fixed_Name1, fixed_Name2)

[8082] Description

[8083] Returns the product of the operands for signed numbers only. Thenumber returned is of the same width as the operands so any bitsproduced by the multiplication outside of this width overflow and arelost.

[8084] Inputs

[8085] fixed_Name1 Signed fixed-point number of any width

[8086] fixed_Name2 Signed fixed-point number of the same width

[8087] Output

[8088] Signed fixed-point number of same width as fixed_Name1

[8089] Detailed Description

[8090] At compile time check fixed_Name1 and fixed_Name2 are of the samewidth and signed type

[8091] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string and sign extend the string by the width of thefraction part of fixed_Name1

[8092] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string and sign extend the string by the width of thefraction part of fixed_Name2

[8093] Multiply these bit strings together

[8094] Drop the fracWidth least significant bits of the result

[8095] Split result into integer and fraction parts of the same type andwidth as fixed_Name1

[8096] Return as struct

[8097] COMP 3.5 FixedMultUnsigned(fixed_Name1, fixed_Name2)

[8098] Description

[8099] Returns the product of the operands for unsigned numbers only.The number returned is of the same width as the operands so any bitsproduced by the multiplication outside of this width overflow and arelost.

[8100] Inputs

[8101] fixed_Name1 Unsigned fixed-point number of any width

[8102] fixed_Name2 Unsigned fixed-point number of the same width

[8103] Output

[8104] Unsigned fixed-point number of same width as fixed_Name1

[8105] Detailed Description

[8106] At compile time check fixed_Name1 and fixed_Name2 are of samewidth and unsigned type

[8107] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string and extend the string with zeros by the width of thefraction part of fixed_Name1

[8108] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string and extend the string with zeros by the width of thefraction part of fixed_Name2

[8109] Multiply these bit strings together

[8110] Drop the fracWidth least significant bits of the result

[8111] Split the result into integer and fraction parts of the same typeand width as fixed_Name1

[8112] Return as struct

[8113] COMP 3.6 FixedDivSigned(fixed_Name1,fired Name2)

[8114] Description

[8115] Returns fixed_Name1 divided by fixed_Name2 for signed numbersonly. The result for fixed_Name2=0 is undefined. The number returned isof the same width as the operands so any bits produced by the divisionoutside of this width are lost.

[8116] Inputs

[8117] fixed_Name1 Signed fixed-point number of any width

[8118] fixed_Name2 Signed fixed-point number of the same width not equalto zero

[8119] Output

[8120] Signed fixed-point number of same width as fixed_Name1

[8121] Detailed Description

[8122] At compile time check fixed_Name1 and fixed_Name2 are of the samewidth and signed type

[8123] Concatenate together the integer and fraction parts offixed_Name1, and zero with the same width as the fraction part, into asingle bit string

[8124] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string and sign extend the string by the width of thefraction part of fixed_Name2

[8125] Divide the first bit string by the second

[8126] Take the least significant bits of the result to make it the samelength as the divided bit string

[8127] Split result of func into integer and fraction parts of same typeand width as fixed_Name1

[8128] Return as struct

[8129] COMP 3.7 FixedDivUnsigned(fixed_Name1, fixed_Name2)

[8130] Description

[8131] Returns fixed_Name1 divided by fixed_Name2 for unsigned numbersonly. The result for fixed_Name2=0 is undefined. The number returned isof the same width as the operands so any bits produced by the divisionoutside of this width are lost.

[8132] Inputs

[8133] fixed_Name1 Unsigned fixed-point number of any width

[8134] fixed_Name2 Unsigned fixed-point number of the same width.

[8135] Output

[8136] Unsigned fixed-point number of same type and width as fixed_Name1

[8137] Detailed Description

[8138] At compile time check fixed_Name1 and fixed_Name2 are of the samewidth and unsigned type

[8139] Concatenate together the integer and fraction parts offixed_Name1, and zero with the same width as the fraction part, into asingle bit string

[8140] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string and extend the string by the width of the fractionpart of fixed_Name2

[8141] Divide the first bit string by the second

[8142] Take the least significant bits of the result to make it the samelength as the divided bit string

[8143] Split result of func into integer and fraction parts of same typeand width as fixed_Name1

[8144] Return as struct

[8145] COMP 3.8 FixedAbs(fixed_Name)

[8146] Description

[8147] Returns the absolute value. The result of using this macro on anunsigned fixed-point structure is undefined. Signed integers use 2'scomplement representation in Handel-C so abs(max positivenumber)<abs(min negative number)

[8148] This means the function gives the result:

[8149] abs(min negative number)=min negative number.

[8150] Inputs

[8151] fixed_Name Fixed-point number of any type and width

[8152] Output

[8153] Fixed-point number of same type and width as fixed_Name

[8154] Detailed Description

[8155] Concatenate integer and fraction parts from fixed_Name into asingle bit string

[8156] Find the absolute value of the bit string

[8157] Split result into integer and fraction parts of same type andwidth as fixed_Name

[8158] Return as struct

[8159] Relational Operators

[8160] The macros in this section rely on Handel-C's type and widthchecking.

[8161] COMP 4.1 FixedEq(fixed_Name1, fixed_Name2)

[8162] Description

[8163] Returns true if the operands are equal.

[8164] Inputs

[8165] fixed_Name1 Fixed-point number of any type or width

[8166] fixed_Name2 Fixed-point number of the same type and width

[8167] Output

[8168] Single bit wide unsigned integer value with 0 as false and 1 astrue

[8169] Detailed Description

[8170] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8171] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8172] True if the bit strings are equal

[8173] Return result

[8174] COMP 4.2 FixedNEq(fixed_Name1, fixed_Name2)

[8175] Description

[8176] Returns true if the operands are not equal

[8177] Inputs

[8178] fixed_Name1 Fixed-point number of any type or width

[8179] fixed_Name2 Fixed-point number of the same type and width

[8180] Output

[8181] Single bit wide unsigned integer value with 0 as false and 1 astrue

[8182] Detailed Description

[8183] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8184] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8185] True if the bit strings are not equal

[8186] Return result

[8187] COMP 4.3 FixedLT(fixed_Name1, fixed_Name2)

[8188] Description

[8189] Returns true if fixed_Name1 is less than fixed_Name2.

[8190] Inputs

[8191] fixed_Name1 Fixed-point number of any type or width

[8192] fixed_Name2 Fixed-point number of the same type and width

[8193] Output

[8194] Single bit wide unsigned integer value with 0 as false and 1 astrue

[8195] Detailed Description

[8196] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8197] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8198] True if the first bit string is less than the second

[8199] Return result

[8200] COMP 4.4 FixedLTE(fixed_Name1, fixed_Name2)

[8201] Description

[8202] Returns true if fixed_Name1 is less than or equal to fixed_Name2.

[8203] Inputs

[8204] fixed_Name1 Fixed-point number of any type or width

[8205] fixed_Name2 Fixed-point number of the same type and width

[8206] Output

[8207] Single bit wide unsigned integer value with 0 as false and 1 astrue

[8208] Detailed Description

[8209] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8210] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8211] True if the first bit string is less than or equal to the second

[8212] Return result

[8213] COMP 4.5 FixedGT(fixed_Name1, fixed_Name2)

[8214] Description

[8215] Returns true if fixed_Name1 is greater than fixed_Name2.

[8216] Inputs

[8217] fixed_Name1 Fixed-point number of any type or width

[8218] fixed_Name2 Fixed-point number of the same type and width

[8219] Output

[8220] Single bit wide unsigned integer value with 0 as false and 1 astrue

[8221] Detailed Description

[8222] Return the result of FixedLT(fixed_Name2, fixed_Name1)

[8223] COMP 4.6 FixedGTE(fixed_Name1, fixed_Name2)

[8224] Description

[8225] Returns true if fixed_Name1 is greater than or equal tofixed_Name2.

[8226] Inputs

[8227] fixed_Name1 Fixed-point number of any type or width

[8228] fixed_Name2 Fixed-point number of the same type and width

[8229] Output

[8230] Single bit wide unsigned integer value with 0 as false and 1 astrue

[8231] Detailed Description

[8232] Return the result of FixedLTE(fixed_Name2, fixed_Name1)

[8233] Bitwise Logical Operators

[8234] The macros in this section rely on Handel-C's type and widthchecking.

[8235] COMP 5.1 FixedNot(fixed_Name)

[8236] Description

[8237] Returns bitwise not.

[8238] Inputs

[8239] fixed_Name Fixed-point number of any type or width

[8240] Output

[8241] Fixed-point number of same type and width as fixed_Name

[8242] Detailed Description

[8243] Concatenate integer and fraction parts from fixed_Name into asingle bit string

[8244] Find the bitwise not of the bit string

[8245] Split result into integer and fraction parts of same type andwidth as fixed_Name

[8246] Return as struct

[8247] COMP 5.2 FixedAnd(fixed_Name1,fixed_Name2)

[8248] Description

[8249] Returns bitwise and.

[8250] Inputs

[8251] fixed_Name1 Fixed-point number of any type or width

[8252] fixed_Name2 Fixed-point number of the same type and width

[8253] Output

[8254] Fixed-point number of same type and width as fixed_Name1

[8255] Detailed Description

[8256] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8257] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8258] Find the bitwise and of the bit strings

[8259] Split result into integer and fraction parts of same type andwidth as fixed_Name1

[8260] Return as struct

[8261] COMP 5.3 FixedOr(fixed_Name1, fixed_Name2)

[8262] Description

[8263] Returns bitwise or.

[8264] Inputs

[8265] fixed_Name1 Fixed-point number of any type or width

[8266] fixed_Name2 Fixed-point number of the same type and width

[8267] Output

[8268] Fixed-point number of same type and width as fixed_Name1

[8269] Detailed Description

[8270] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8271] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8272] Find the bitwise or of the bit strings

[8273] Split result into integer and fraction parts of same type andwidth as fixed_Name1

[8274] Return as struct

[8275] COMP 5.4 FixedXor(fixed_Name1, fixed_Name2)

[8276] Description

[8277] Returns bitwise and.

[8278] Inputs

[8279] fixed_Name1 Fixed-point number of any type or width

[8280] fixed_Name2 Fixed-point number of the same type and width

[8281] Output

[8282] Fixed-point number of same type and width as fixed_Name1

[8283] Detailed Description

[8284] Concatenate integer and fraction parts from fixed_Name1 into asingle bit string

[8285] Concatenate integer and fraction parts from fixed_Name2 into asingle bit string

[8286] Find the bitwise and of the bit strings

[8287] Split result into integer and fraction parts of same type andwidth as fixed_Name1

[8288] Return as struct

[8289] Conversion Operators

[8290] COMP 6.1 FixedIntWidth(fixed_Name)

[8291] Description

[8292] Returns the width of the integer part of fixed_Name as a compiletime constant.

[8293] Inputs

[8294] fixed_Name1 Fixed-point number of any type or width

[8295] output

[8296] Compile time constant integer

[8297] Detailed Description

[8298] Return the width of the integer part of fixed_Name

[8299] COMP 6.2 FixedFracWidth(fixed_Name)

[8300] Description

[8301] Returns the width of the fraction part of fixed_Name as a compiletime constant.

[8302] Inputs

[8303] fixed_Name1 Fixed-point number of any type or width

[8304] Output

[8305] Compile time constant integer

[8306] Detailed Description

[8307] Return the width of the fraction part of fixed_Name

[8308] COMP 6.3 FixedLiteral(isSigned, intWidth, fracWidth, intBits,fracBits)

[8309] Description

[8310] Returns a signed fixed-point number if isSigned is true and anunsigned fixed-point number if isSigned is false. This number has aninteger part intBits of width int Width and a fraction part fracBits ofwidthfracWidth.

[8311] Inputs

[8312] isSigned Compile time constant to indicate the type offixed-point structure.

[8313] FIXED_ISSIGNED represents signed and FIXED_ISUNSIGNED unsigned

[8314] intWidth Compile time constant integer to set width of integerpart

[8315] fracWidth Compile time constant integer to set width of fractionpart

[8316] intBits Value to set integer part

[8317] fracBits Value to set fraction part

[8318] Output

[8319] Signed or unsigned fixed-point number with widths and valuesspecified

[8320] Detailed Description

[8321] Selects signed or unsigned type to cast structure using isSigned

[8322] Return a fixed-point number with an integer part of widthintWidth and value intBits, and a fraction part of width fracWidth andvalue fracBits

[8323] COMP 6.4 FixedToInt(fixed_Name)

[8324] Description

[8325] Returns the integer part of the fixed point number with the sametype and width.

[8326] Inputs

[8327] fixed_Name Fixed point number of any type or width

[8328] Output

[8329] Integer of same type and width as the integer part of the numberis stored in the fixed point structure

[8330] Detailed Description

[8331] Return the integer part of the fixed point number

[8332] COMP 6.5 FixedToBool (fixed_Name)

[8333] Description

[8334] Returns a single bit wide unsigned int value which is 0 for falseif the operand equals 0 and 1 for true otherwise.

[8335] Inputs

[8336] fixed_Name Fixed-point number of any type or width

[8337] Output

[8338] Single bit wide unsigned integer value with 0 as false and 1 astrue

[8339] Detailed Description

[8340] Return 1 if the fixed and the fraction parts of fixed_Name areboth not equal to zero and 0 otherwise

[8341] COMP 6.6 FixedToBits(fixed_Name)

[8342] Description

[8343] Returns the integer and fraction bits of fixed_Name concatenatedtogether.

[8344] Inputs

[8345] fixed_Name Fixed-point number of any type or width

[8346] Output

[8347] Integer of same type as the fixed-point structure and with widthintWidth+fracWidth

[8348] Detailed Description

[8349] Return the integer part and the fraction part of the fixed-pointnumber concatenated together

[8350] COMP 6.7 FixedCastSigned(isSigned, intWidth, fracWidth,fixed_Name)

[8351] Description

[8352] Casts any signed fixed-point number to the type and widthsspecified.

[8353] Inputs

[8354] isSigned Compile time constant to indicate the type offixed-point structure.

[8355] FIXED_ISSIGNED represents signed and FIXED_ISUNSIGNED unsigned

[8356] intWidth Width to cast the integer part of the number to

[8357] fracWidth Width to cast the fraction part of the number to

[8358] fixed_Name Fixed-point number of signed type and any width

[8359] Output

[8360] Fixed-point number of the type specified

[8361] Detailed Description

[8362] Adjust the integer part of fixed_Name to a width of intWidth byeither taking the intWidth least significant bits or sign extending.

[8363] Adjust the fraction part of fixed_Name to a width of fracWidth byeither taking the frac Width most significant bits or adding bits withvalue zero in after the number.

[8364] If isSigned is true then cast the integer and fraction parts ofthe floating point number as signed

[8365] If isSigned is false then cast the integer and fraction parts ofthe floating point number as unsigned

[8366] Return the result as a struct

[8367] COMP 6.8 FixedCastUnsigned(isSigned, intWidth, fracWidth,fixed_Name)

[8368] Description

[8369] Casts any unsigned fixed-point number to the type and widthsspecified.

[8370] Inputs

[8371] isSigned Compile time constant to indicate the type offixed-point structure.

[8372] FIXED_ISSIGNED represents signed and FIXED_ISUNSIGNED unsigned

[8373] intWidth Width to cast the integer part of the number to

[8374] fracWidth Width to cast the fraction part of the number to

[8375] fixed_Name Fixed-point number of unsigned type and any width

[8376] Output

[8377] Fixed-point number of the type specified

[8378] Detailed Description

[8379] Adjust the integer part of fixed_Name to a width of intWidth byeither taking the intWidth least significant bits or adding bits withvalue zero in front of the number.

[8380] Adjust the fraction part off fixed_Name to a width of fracWidthby either taking the fracWidth most significant bits or adding bits withvalue zero in after the number.

[8381] If isSigned is true then cast the integer and fraction parts ofthe floating point number as signed

[8382] If isSigned is false then cast the integer and fraction parts ofthe floating point number as unsigned

[8383] Return the result as a struct

[8384] Verification

[8385] This section documents all of the tests necessary to verify thateach macro functions correctly. It is important that the macros matchtheir definitions in the subsections above. All of the macros availableto the user can be tested for results and errors using black boxtesting.

[8386] Runtime tests:

[8387] The type performed are:

[8388] Positive (P)

[8389] Negative (N)

[8390] Volume and Stress (V&S)

[8391] Comparison (C)

[8392] Demonstration (D)

[8393] The tests are performed only on 8 and 32 bit numbers apart fromwhen it seems appropriate to use other widths also to fully test themacro, such as for FixedIntWidth. The tests are performed on signed andunsigned numbers apart from when this is not possible because the macrois only designed for one type. Generally the tests are aimed at:

[8394] Zero values (P, V&S, C, D)

[8395] Midrange values (P, V&S, C, D)

[8396] Overflow values (N, V&S, C, D)

[8397] The results expected for the comparison tests have beencalculated using the Microsoft Calculator

[8398] Error tests:

[8399] These are tests which may produce non-severe errors from thecompiler. They should be either standard Handel-C error messagesdirected at the functions used or assert errors defined in the library.Generally the tests performed may be:

[8400] inputting an integer into where there should be a fixed-pointstructure

[8401] inputting a signed fixed-point structures where there should bean unsigned fixed-point structure and vice versa

[8402] inputting two fixed-point structures of different types or widthin the same macro

[8403] inputting an integer of incorrect width

[8404] inputting variables when a constant is required

[8405] assigning fixed-point result to a fixed-point structure ofincorrect type or width

[8406] assigning integer result to a int of incorrect type or width

[8407] Performance tests:

[8408] All of the macros take just one clock cycle to run. In the caseof the arithmetic operators, the number of SLICEs and maximum speed maybe calculated to compare with the appropriate Handel-C operator.

Waveform Analsis

[8409] Trace/pattern Window

[8410]FIG. 93 illustrates a Trace and Pattern window 9300. In the Traceand Pattern window, the top half 9302 of the window shows the trace orpattern details. The bottom half 9304 of the window shows the values andpositions of marks that have been set on the trace or pattern. The marksare referred to as cursors and represented by colored triangles.

[8411] In an illustrative embodiment, the current trace is out-linedwith a green dashed line. The current cursor has a red underline.Right-clicking the trace waveform or the current value pane calls up amenu of possible display formats for that pane. Multiple traces orpatterns in a single window, but they all use the same cursors, the samenumber of points and the same clock period.

[8412] Zooming

[8413] A user may zoom in and out of the active Trace or Pattern windowusing the zoom icons or the Zoom options from the View menu.

[8414] Set Advance Step Dialog

[8415] The Set Advance Step dialog (Capture>Set Advance Step) specifiesthe time in nanoseconds to advance all simulations by.

[8416] Capture Menu

[8417] Several items of a capture menu according to an embodiment of thepresent invention include the following set forth in Table 23. TABLE 23Run(F5) Start reading traces from simulations and sending patterns tosimulations. Pause Temporarily stop sending traces to simulations andreading patterns from simulations. This may also suspend all connectedsimulations. Stop Stop reading traces from simulations and sendingpatterns (Shift + F5) to simulations. Simulations may continue runningafter Waveform Analyzer has stopped. Advance Advance all simulations bythe specified interval. (Ctrl + F11) Set Advance Specify the interval bywhich to advance simulations Step when ‘Advance’ is selected. Opens SetAdvance Step dialog.

[8418] Define Symbols Dialog Box

[8419] The Define symbols dialog box consists of a set of radio buttonswhich allow selection of bow values are represented:

[8420] Binary

[8421] Octal

[8422] Decimal

[8423] Hexadecimal numbers

[8424] ASCII characters

[8425] User defined strings: The user may supply the filename of a filewhich associates symbols with values for the trace being defined. Eachline of this file should contain a number (in binary, octal, decimal orhexadecimal, using the Handel-C syntax) followed by a symbol. The symbolshould be separated from the number using a whitespace. Any values whichmay appear in the Trace and which do not have symbols associated withthem may be represented using the ‘?’ character. For example, if thetrace is of width 3, is unsigned, and the user defined symbol filecontains the following: 0b001 A 0b111 D 0b110 C

[8426]0b101 B

[8427] the values 1,5,6 and 7 may be represented as A,B,C and Drespectively. The values 0,2,3 and 4 may all be represented as questionmarks.

[8428] Edit Menu

[8429] Items in the Edit Menu include those set forth in Table 24. TABLE24 Find Search for a specified sequence of data words in the selectedtrace or (Ctrl + F) patten. The user is prompted for a PGL statementdescribing the sequence of words to search for, the search direction,and whether to scroll to the sequence if it is found. Searching startsat the position of the selected cursor. If there is no cursor, searchingstarts at the beginning of the selected trace or pattern. If thesequence is found, the selected cursor is positioned at the start of thesequence. If there is no cursor, a cursor is created at the start of thesequence. Copy Copy the selected portion of the selected trace orpattern to the (Ctrl + C) clipboard. Paste Paste the contents of theclipboard into the selected portion of the (Ctrl + V) selected pattern.Save Save the selected portion of the selected trace or pattern to afile. Selection As . . . The user is prompted for a filename and, if thefile is a VCD file, a reference name to use for the signal in the VCDfile.

[8430] File Menu

[8431] Items in the Edit Menu include those set forth in Table 25. TABLE25 New Open a new trace or pattern dialog. The user is (Ctrl + N)prompted for the type of window, a filename for the window and the clockperiod and number of points for the window. The clock period and thenumber of points that the user specifies may be used for all traces orpatterns in the window. Open Open an existing trace or pattern file.(Ctrl + O) Close Close the active trace or pattern window. Save Save theactive trace or pattern window. (Ctrl + S) Save As Save the active traceor pattern window with a different name. Save All Save all open traceand pattern windows. New Project Create a new project. Open Project Openan existing project. Close Close the current project. Project SaveProject Save the current project. Print Print the active trace orpattern window. Print Setup Setup the printer details. Print Preview theactive trace or pattern window. Preview Recent Files A list of recentlyused trace or pattern files. Recent A list of recently used projects.Projects Exit Close all windows and exit the application.

[8432] New Window Dialog

[8433] The New window dialog box (File>New) defines the default clockperiod and the number of points in the window. Elements include thoseset forth in Table 26. TABLE 26 Untitled box Enter the window nameDefault clock Enter the default clock period in nanoseconds periodDefault No. Enter the number of points recorded in the window pointsFilename and File where the window details are stored (use the locationbrowse button to choose a directory

[8434] Pattern Menu

[8435] Items in the Edit Menu include those set forth in Table 27. TABLE27 New Pattern Create a new pattern in the active pattern window. EditPattern Edit the selected pattern in the active pattern window. DeletePattern Remove the selected pattern from the active pattern window.

[8436] Pattern Properties Dialog Box

[8437] The fields in the Pattern properties dialog box include those setforth in Table 28. TABLE 28 Name Name to use for the pattern. The nameis displayed in a box on the left of the Pattern window. The name may bea C-style identifier. Width Width of the data in the pattern in bits.Type Whether the pattern represents signed or unsigned data. PointsNumber of points in the pattern. This value was entered when the PatternWindow was created. It cannot be edited. Clock Period Rate at which datais read into the pattern. This value was entered when the Pattern windowwas created. It cannot be edited. Source The source for the pattern maybe either a file or a script. Supported file formats are ASCII and VCD.The box to the right of the radio buttons is used to enter a script ifthe ‘Script’ radio button is checked, or a file name if the ‘File’ radiobutton is checked. Variable If the source is a VCD file, this box shouldbe used to enter the reference name of the variable in the VCD file thatmay be used as the source for this pattern. Destination Expression ofthe form ‘Terminal-Name(width)’ as for the DK1Connect plugin TriggerTransmission of a pattern can be triggered by the occurrence of aspecified sequence of words in any trace. This box is used to specifywhich sequences of words and which trace triggering should occur on Ifthis box is empty, no trigger is used and all further trigger optionsare grayed out. Delay Specifies the trigger delay. For patterns, thismay be positive. A delay of x means that transmission begins x timeunits after a trigger sequence occurs. No Choose the trigger mode.trigger/Single/ No trigger, triggering is disabled. Auto Single, apattern is transmitted once after a trigger sequence occurs. Auto, apattern is transmitted after every occurrence of a trigger sequence.Pause on If this checkbox is ticked, capturing may Trigger automaticallyget paused after a trigger sequence has occurred and a pattern has beentransmitted. Interpolated This set of radio buttons is used to choosethe Waveform/ display format for the pattern. Stepped Waveform/ NumericSymbolic Define Select how values are represented Symbols (gives dialog)

[8438] Grouping Windows Into Projects

[8439] Trace Windows and Pattern Windows can be grouped together intoprojects. Only one project may be open at a time. The user may create aproject if he or she wants to use a Pattern Generation Language Scriptfile.

[8440] Creating a Project

[8441] Open Waveform Analyzer and select New Project from the File menu.

[8442] A dialog box appears asking the user to select a file name forthe new project. Project filenames have an ‘.APJ’ extension.

[8443] Script Menu

[8444] The script menu includes the following item:

[8445] Edit Script . . . Edit the PGL script for the current project.

[8446] Trace Dialog

[8447] Fields in the Trace properties dialog box (Trace>New Trace)include the following set forth in Table 29. TABLE 29 Field FunctionName Name to use for the trace. This name may be displayed in a box onthe left of the Trace window. The name can also be used as part of atrigger specification for this or any other trace. The name may be aC-style identifier. Width Width of the data in the trace in bits. TypeWhether the trace represents signed or unsigned data. Points Number ofpoints in the trace. This value was entered when the Trace window wascreated. It cannot be edited. Clock Period Rate at which data is readinto the trace. This value was entered when the Trace window wascreated. It cannot be edited. Expression Port(s) the trace is connectedto. The expression may be of the form ‘Terminal-Name(width)’ (as for theDK1 Connect plugin) or a Handel-C expression with expressions of theform ‘Terminal- Name(width)’ in place of variables. Dump File Enter afilename to capture the trace to a file. Two file formats are supported:ASCII files and Verilog Value Change Dump files. If the filename ends in‘.VCD’, ‘.DMP’ or ‘.DUMP’ a Value Change Dump file may be producedotherwise an ASCII file may be produced. The Browse button may be usedto select a filename. If no filename is entered, no dump file may beproduced. Variable If the dump file is a Verilog Value Change Dump file,enter the name which may be used as the reference name of the signal inthe VCD file. Trigger Specifies which sequences of words triggeringshould occur on If this box is empty, no trigger is used and all furthertrigger options aregrayed out. Delay Specifies the trigger delay. Thismay be positive or negative. If a positive delay x is used, capturingbegins x time units after a trigger sequence occurs. If a negative delayis used, capturing begins x time units before a trigger sequence occurs.No trigger/Single/Auto Select trigger mode. No trigger, triggering isdisabled. Single, a trace is captured once after a trigger sequenceoccurs. Auto, a trace is captured after every occurrence of a triggersequence. Pause on Trigger If this checkbox is ticked, capturing mayautomatically get paused after a trigger sequence has occurred and atrace has been captured. Interpolated Select display format for trace.Waveform/Stepped Waveform/Numeric Symbolic Define Symbols (gives Selecthow values are represented dialog)

[8448] Trace Menu

[8449] Fields in the trace menu include those set forth in Table 30.TABLE 30 New Trace Create a new trace in the active Trace window. EditTrace Edit the selected trace in the active Trace window. Delete TraceRemove the selected trace from the active Trace window.

[8450] View Menu

[8451] Items available from the view menu include those set forth inTable 31. TABLE 31 Toolbar Toggle the toolbar on/off. Status Bar Togglethe Status Bar on/off. Zoom Max Zoom in to the maximum extent at thecentre of the active trace or pattern window. Zoom In Zoom in at thecentre of the active trace or pattern window. Zoom Out Zoom out from thecentre of the active trace or pattern window. Zoom Min Zoom out to themaximum extent from the centre of the active trace or pattern window.Zoom on Cursor Zoom in on the selected cursor in the active trace orpattern window. Jump to Cursor Scroll to the selected cursor in theactive trace or pattern window. New Cursor Create a new cursor in thecentre of the active trace or pattern window. Delete Cursor Delete theselected cursor from the active trace or pattern window.

[8452] Toolbar Icons

[8453]FIG. 94 illustrates several toolbar icons 9400 and their functions9402.

[8454] Window Menu

[8455] Items in the window menu include those set forth in Table 32.TABLE 32 Cascade Cascade all open windows. Tile Tile all open window.Arrange Icons Automatically arrange all minimized trace and patternwindows.

[8456] Analyzer Interface

[8457] The waveform analyzer interface consists of:

[8458] menu bar

[8459] tool bar

[8460] workspace area

[8461] any trace or pattern windows open

[8462] log output window: used by the program to report errors to theuser.

[8463] The user may group trace or pattern windows together in aproject. Projects contain a number of trace or pattern windows (thoseopen when during the last save of the project) and any scripts writtenin the project.

[8464] Menus

[8465] File Menu

[8466] New windows dialog (File>New)

[8467] Edit Menu

[8468] View Menu

[8469] Trace Menu

[8470] Trace dialog

[8471] Pattern Menu

[8472] Pattern properties dialog

[8473] Define symbols dialog

[8474] Script Menu

[8475] Capture Menu

[8476] Window Menu

[8477] Help Menu

[8478] Pattern Generation Language

[8479] The Waveform Analyzer uses Pattern Generation Language (PGL) as ascripting language to generate patterns. PGL has a similar expressivepower to regular expressions, but uses a C-like syntax.

[8480] The PGL can be used to trigger on a sequence of data and searchfor a sequence of data in a trace or pattern.

[8481] When executed, a PGL program generates a sequence of values. Whenused for triggering or searching, a program in PGL may match anysequence which it could generate, such as:

[8482] PGL statements

[8483] PGL functions

[8484] Wild-card matching

[8485] Pattern Generation Language syntax

[8486] Using the Waveform Analyzer

[8487] The Waveform Analyzer connects to ports in Handel-C simulations.It displays outputs from Handel-C simulations as waveforms (traces).Thus a user can generate inputs to Handel-C simulations and display themas waveforms (patterns). The user can also manipulate the simulatedinputs and outputs in the same way that input and output signals from areal piece of hardware can be manipulated with a waveform analyzer. Apartial list of manners in which the waveform analyzer can be usedfollows.

[8488] Connecting traces to output ports in Handel-C simulations

[8489] Connecting patterns to input ports in Handel-C simulations

[8490] Connecting the Waveform Analyzer to ports connected to anothersimulation using the DK1Share plugin (connecting in parallel)

[8491] Measuring the differences between values and times in traces orpatterns using cursor marks.

[8492] Creating patterns by writing scripts using a Pattern GenerationLanguage, or by copying existing traces or patterns into a patternwindow. Patterns can also be read from a file.

[8493] Specifying triggers in the Pattern Generation Language

[8494] Capturing traces or generate patterns when a specified triggerappears in a trace

[8495] Finding a specified pattern in a trace or pattern window

[8496] Functions in PGL

[8497] PGL allows a user to define and call functions which can takeparameters. Only functions in an open project can be defined. Thefunctions are stored in the script.pgl file associated with thatproject. The user may edit this file outside the Waveform Analyzer.

[8498] Defining Functions

[8499] To define functions, the project where the functions are to beused is opened. The ‘Edit Script’ icon on the toolbar is selected.Alternatively, Edit Script from the Script menu can be selected: thefile script.pgl is opened in Notepad. This file resides in the samedirectory as the project file.

[8500] Example

[8501] The following example defines two functions, one called risingedge and the other called rectangular_wave. rising_edge() {0;1;}rectangular_wave(hival,hicount,loval,locount,cycles) { loop (cycles) {loop(hicount) hival; loop(locount) loval; } }

[8502] The rectangular_wave function can be called with a statement likethe following:

[8503] rectangular_wave(1,5,0,5,10);

[8504] Wild-card Matching in Triggering or Searching

[8505] When a PGL program is used for triggering or searching, it maycontain a ‘?’ character in any place where a number or variable couldgo. This character stands for ‘any value’. For example the compoundstatement {1;?;1;} would match against any 3 word sequence starting andending with a 1.

[8506] If ‘?’ is used as an actual parameter in a function call, whenthe function is called, the formal parameter which corresponds to the‘?’ has no value assigned to it.

[8507] If a variable is encountered which has no value assigned to it,it gets assigned a value according to the values encountered duringmatching.

[8508] Context-sensitive matches can be carried out in this way. Forexample, if a function is defined as follows:

[8509] count_fives(a)

[8510] {a; loop(a) 5;}

[8511] and called using the statement ‘count_fives(?);’, it may matchany sequence consisting of a number, followed by that number of fives(including the sequence ‘0’). This feature should be used carefully,since it is possible to use it write functions which take a very longtime to match.

[8512] PGL Statements

[8513] The pattern generation language consists of one or morestatements terminated by semi-colons. Statements can include numbers,identifiers and wild-cards. A PGL statement may be one of the following:

[8514] Expression Statement

[8515] For example:

[8516] 1;

[8517] When an expression statement is executed, it generates the valueof the expression.

[8518] An expression statement used for matching may also be of theform:

[8519] !1;

[8520] This statement may match any value except 1.

[8521] Compound Statement

[8522] For example: {0;1;}

[8523] The statements enclosed in the curly brackets get executedsequentially.

[8524] Loop Statement

[8525] For example: loop(3) {0;1;}

[8526] The body of this loop may get executed 3 times.

[8527] Conditional Statement

[8528] For example:

[8529] if(a==1) {0;1;} else {1;0;}

[8530] Here, the statements which get executed depend upon the value ofthe variable a.

[8531] A user can build Boolean tests using the following operators touse for the condition in a conditional statement:

[8532] ==!=!∥&&

[8533] Switch Statement

[8534] For example: switch(a) { case 1: 0; 1; break; default: 1; 0;break; }

[8535] This switch statement achieves the same thing as the if—elsestatement described above.

[8536] Assert Statement

[8537] For example:

[8538] assert(a !=0);

[8539] This kind of statement can be used when matching to placeconstraints on matched variables.

[8540] Wild-card matching in PGL

[8541] If a PGL program is used for triggering or searching, a ‘?’character can be used in any place where a number or variable could go.This character stands for ‘any value’. For example the compoundstatement {1;?;1;} would match against any 3 word sequence starting andending with a 1.

[8542] If ‘?’ is used as an actual parameter in a function call, whenthe function is called, the formal parameter which corresponds to the‘?’ has no value assigned to it. If a variable is encountered which hasno value assigned to it, it gets assigned a value according to thevalues encountered during matching. Context-sensitive matches can becarried out in this way. For example, a function defined as follows:

[8543] count_fives(a)

[8544] {a; loop(a) 5;}

[8545] If this is called using the statement ‘count_fives(?);’, it maymatch any sequence consisting of a number, followed by that number offives. (Including the sequence ‘0’). This feature should be usedcarefully, since it is possible to use it write functions which take avery long time to match.

[8546] It is an error to use the ‘?’ expression, expression statementsstarting with ‘!’ and assert statements in PGL programs which are usedto generate patterns.

[8547] Connecting in Parallel

[8548] If it is desired to connect the Waveform Analyzer to ports thatare connected to another simulation, this may be done using theDK1Share.dll.

[8549] Example interface bus_out() seg7_output(unsigned 7 output 1 =encode_out) with {extlib=“DK1Share.dll”, extinst=“♯Share={extlib=<7segment.dll>, extinst=<A>, extfunc=<PlugInSet>} ♯Share={extlib=<DK1Connect.dll>, extinst=<SS(7)>,extfunc=<DK1ConnectGetSet>} ♯ ”, extfunc=“DK1ShareGetSet” };

[8550] This example uses DK1Share.dll to share the output portseg7_output.output1 between the 7-segment display (connected to terminalA) and DK1Connect (connected to terminal SS(7)). A user can then tracethe output going to the 7-segment display by using SS (7) as theexpression in the Trace properties window

[8551] Finding a Sequence of Data in a Trace or Pattern

[8552] To find a sequence of data, the window that contains the trace orpattern to be searched is activated. If there are multiple traces orpatterns in the window, the desired trace or pattern is selected. TheEdit>Find menu item is selected. A PGL statement or function is enteredin the ‘Find what:’ box in the Find dialog.

[8553] Generating Patterns

[8554] Generating a Pattern From an Existing Trace or Pattern

[8555] Data is copied from a trace or pattern into the clipboard, andthen the contents of the clipboard are pasted into a pattern. A regionof a trace or pattern is selected, such as by dragging the mouse pointerover the region to select it. The region is copied to the clipboard byselecting Copy from the Edit menu or with the Copy icon on the toolbar.A pattern window is activated and either a region to paste over or acursor is selected. Paste is selected from the Edit menu or the Pasteicon on the toolbar is clicked on.

[8556] If a region has been selected, the clipboard contents are pastedinto the selected pattern starting at the beginning of the selectedregion. If a cursor was selected, the clipboard contents are pasted intothe window starting at the selected cursor location.

[8557] Generating a Pattern From a PGL Statement:

[8558] Script is selected as the pattern source in the PatternProperties dialog. The PGL statement or function call is entered in thebox to the right of the button.

[8559] Generating a Pattern from a File:

[8560] File is selected as the pattern source in the Pattern Propertiesdialog. The filename is entered in the box to the right of the button.The Browse button is used to browse for a file.

[8561] Pattern Generation Limitations

[8562] It is an error to use the ‘?’ expression, expression statementsstarting with ‘!’ and assert statements in PGL programs which are usedto generate patterns.

[8563] Complex Pattern-generation

[8564] More complex patterns may require using a separate Handel-Cprogram to perform pattern generation.

[8565] Measuring Time and Value Differences in Windows

[8566] The user can measure the time between two events and thedifference in the value of a signal at two different times by placingmarks in Trace and Pattern Windows. These marks are represented bycolored triangles and may be referred to as cursors. One cursor isalways selected.

[8567] The cursor triangles are placed in the time pane of the trace orpattern window. If there is more than one cursor in the time pane, thetime pane displays the differences in time between cursors. Thebottom-centre pane displays the absolute position in time of allcursors. The differences in values between the cursors are displayed inthe bottom-left pane.

[8568] If multiple traces or patterns are displayed in a window, thevalues given are those of the selected trace or pattern.

[8569] Creating Cursors

[8570] Click on the New cursor icon on the toolbar or select New Cursorfrom the View menu. The cursor may be added to the center of the timepane of the active trace or pattern window.

[8571] Moving Cursors

[8572] Drag the cursor across the time pane

[8573] Selecting Cursors

[8574] Double-click a cursor. A red bar may appear beneath it to showthat it is selected. By default, the first cursor created is theselected cursor. Only one cursor can be selected at a time.

[8575] Deleting Cursors

[8576] Select the cursor to be deleted. Click the Delete Cursor icon onthe toolbar or select Delete Cursor from the View menu.

[8577] Connecting a Pattern to a Port

[8578] To connect a pattern to a port, the following steps areperformed:

[8579] 1. write and compile Handel-C code to connect a Handel-C port toa terminal using the DK1Connect and the DK1 Sync plugins.

[8580] 2. set up a pattern window in the analyzer generating a signal tothe named terminal.

[8581] 3. simulate the Handel-C code and start transmitting the pattern

[8582] Writing the Handel-C Program

[8583] To write a program in Handel-C, open Handel-C, create a newproject and enter the following program: set clock = external “P1” with{extlib = “DK1Sync.dll”, extinst = “50”, extfunc = “DK1SyncGetSet”};interface bus_in(unsigned 1 in) ib1() with {extlib = “DK1Connect.dll”,extinst = “t(1)”, extfunc = “DK1ConnectGetSet“}; unsigned 5 count = 0;void main(void) { while(!count[4] ∥ !count[2]) { if (ib1.in == 0) {delay; if (ib1.in == 1) count++; } else delay; } }

[8584] Note: this program uses the DK1Connect plugin to connect the portib1.in to the terminal t(1) The program may only terminate when it hasdetected 20 rising edges from the port ib1.in.

[8585] Set up a Pattern Window

[8586] To set up a pattern window, the following general steps areperformed:

[8587] 1. Open Waveform Analyzer.

[8588] 2. In Waveform Analyzer, select New from the File menu and createa new pattern with a filename, with 40 as the number of points and 50 asthe clock period.

[8589] 3. An empty Pattern window appears. Select New Pattern from thePattern menu or from the toolbar and enter the following properties inthe dialog box. Note Table 33. TABLE 33 Name: testpattern Width: 1 Type:Unsigned Source: Select Script radio button. Enter loop(20) {0;1;} inthe box. Variable: Grayed out. Destination: t(1) Trigger: Leave boxblank. Other settings should be grayed out. Delay: Grayed out with 0 asdefault Display: Check Stepped Waveform radio button 4. Click OK.

[8590] Start Transmission

[8591] To start the transmission, tun the Handel-C simulation. Starttransmission by clicking the Run icon on the toolbar, or by selectingRun from the Capture menu. The Handel-C program should terminate shortlyafter transmission is started. To stop capturing click on the stop iconon the toolbar or select Stop from the Capture menu.

[8592] Starting the Waveform Analyzer

[8593] To start the Waveform Analyzer:

[8594] Select Start>Programs>DK1 Design Suite>Waveform Analyzer or,

[8595] Double-click the icon for the analyzer.exe file in the DK1\Bindirectory.

[8596] Connecting a Simulation to a Trace

[8597] To connect a simulation to a trace:

[8598] 1. write and compile Handel-C code to connect a Handel-C port toa terminal using the

[8599] DK1Connect and the DK1 Sync plugins.

[8600] 2. set up a trace window in the analyzer which reads the signalfrom the named terminal.

[8601] 3. simulate the Handel-C code and start capturing Sample Handel-Cprogram set clock = external “P1” with {extlib = “DK1Sync.dll”, extinst= “50”, extfunc =“ DK1 SyncGetSet”}; unsigned 3 x = 0; interfacebus_out() ob1(unsigned 3 out = x) with {extlib = “DK1Connect.dll”,extinst =“t(3)”, extfunc = “DK1ConnectGetSet ”}; void main(void) {while(1) x++; }

[8602] Note: this program uses the DK1Connect plugin to connect the portob1.out to the terminal t(3). Compile the program but do not run it.

[8603] Set up a Trace Window

[8604] To set up a trace window, open Waveform Analyzer. In WaveformAnalyzer, select New from the File menu and create a new trace. Selectthe browse button to specify a filename and location. Set Default ClockPeriod to 50 and Default No. points to 40.

[8605] An empty Trace window should appear. Select New Trace from theTrace menu or from the toolbar and enter the following properties in thedialog box. Note Table 34. TABLE 34 Name: testtrace Width: 3 Type:Unsigned Expression: t(3) Dump File: Leave blank Variable: Grayed outTrigger: Leave box blank. Other settings should be grayed out. Delay:Grayed out with 0 as default Display: Check the Stepped Waveform radiobutton. Click OK.

[8606] Start Capturing

[8607] Start capturing by clicking the Run icon on the toolbar, or byselecting Run from the Capture menu. A red dashed line should appear(jumping around all over the place). This line marks the currentposition in the trace. Run the Handel-C simulation. To stop capturingclick on the stop button on the toolbar or select Stop from the Capturemenu. The Handel-C simulation is stopped.

[8608] Using the Pattern Generation Language

[8609] The Pattern Generation Language (PGL) can be used to:

[8610] Generate patterns that are fed into a port

[8611] Identify a sequence of data in a trace to use as a trigger. Thetrigger can be used to start recording the trace or to start generatinga pattern. If a trigger associated with a trace or pattern has beendefined, it may be re-used as a trigger for other traces or patterns.

[8612] Find a sequence of data in a trace or a pattern

[8613] Entering PGL Statements

[8614] PGL is entered as a single PGL statement in the properties dialogfor a trace or pattern. The PGL statement may be a compound statement ora function call. PGL functions may be written in the script.pgl fileassociated with a project.

[8615] Complex Pattern-matching and Pattern-generation

[8616] A separate Handel-C program can be written to perform patterngeneration or pattern matching. For triggering, a trigger signal can beoutput from this Handel-C program to Waveform Analyzer, and then asimple PGL statement can be used to trigger on this signal.

[8617] Using Triggers

[8618] A sequence of data to be used as a trigger can be specified.Alternatively, an existing specification can be used.

[8619] When the trigger sequence occurs, the following are enabled:

[8620] Start capturing a trace before, at or after the specified trigger

[8621] Start generating a pattern at or after the specified trigger

[8622] Stop capturing a trace or generating a pattern.

[8623] To Specify a Trigger:

[8624] Open the Pattern or Trace Properties dialog. Enter trace name: inthe Trigger box followed by a PGL statement. trace name is the name of apre-defined trace (Note that it may be followed by a colon). The PGLstatement may be matched against the named trace. For example:

[8625] b: {0;1;}

[8626] would cause the pattern to be generated on a rising edge of traceb. The appropriate radio button is selected. Radio buttons include thoseset forth in Table 35. TABLE 35 No trigger: No triggering Single:Transmit or capture the first time the trigger is received Auto:Transmit or capture each time the trigger is received.

[8627] To re-use a specified trigger, “name is entered in the Triggerbox, where name is the name of the trace or pattern that uses a trigger.Note that name may be preceded by a double-quote. For example:

[8628] “trace1

[8629] would cause the trace or pattern whose details are being enteredto use the same trigger as the trace named trace1. The appropriate radiobutton is selected. Note Table 36. TABLE 36 No trigger: No triggeringSingle: Transmit or capture the first time the trigger is received Auto:Transmit or capture each time the trigger is received.

[8630] To Specify the Delay Between the Trigger and the Action

[8631] Specify a trigger and enter the number of time units in the Delaybox on the Properties dialog. The delay is in the time units for thatwindow. Delays can be positive or negative for a trace, (negative delayscapture before the trigger, positive after) and positive or zero for apattern.

[8632] To Pause on Trigger

[8633] Specify a trigger and check the Pause box.

[8634] File Formats

[8635] A preferred embodiment of the Waveform Analyzer supports twodifferent file formats for storing waveform data. These can include, forexample ASCII files, where data elements are written in ASCII andseparated by whitespace; and Value Change Dump (VCD) files. This fileformat is specified in the IEEE 1364 standard.

[8636] A VCD file can contain any number of variables. If several tracesare dumped to the same VCD file, simply enter the same VCD filename inthe ‘Dump File’ box for every trace which should be written to thatfile. The ‘Variable’ box in the Trace dialog is used to enter areference name which may be used in the VCD file for the signal.

[8637] When reading a pattern from a VCD file, the ‘Variable’ box in thePattern dialog is used to enter the reference name of the variable inthe VCD file which needs to be read.

[8638] The file extension of a Dump File or Pattern source filedetermines the file format. If the extension is ‘.VCD’, ‘.DMP’ or‘.DUMP’ the file is a Value Change Dump file, otherwise it is an ASCIIfile.

[8639] Pattern Generation Language Syntax

[8640] The following are syntax statements used during programming:subprogram_def : := identifier ( [parameter-list] ) compound-statementparameter-list : := identifier | identifier , parameter-list statements: := statement | statement statements statement : :=subprogram_call|compound-statement |loop-statement |if-statement |if-else-statement|switch-statement |break-statement |expression-statement|assert-statement subprogram_call : := identifier ([expression-parameter-list] ) ; expression-parameter-list : :=expression |  expression, expression-parameter-list compound-statement ::= { statements } loop-statement : := loop ( expression ) statement|  loop forever statement if-statement ::= if (boolean-expression )statement if-else-statement ::= if ( boolean-expression ) statement elsestatement switch-statement : := switch ( expression ) { case-list[default : statements] } case-list : :=case |  case case-list case ::= case number : statements break-statement : := break ;expression-statement : :=expression ; |  !expression ; assert-statement: := assert ( boolean-expression ); boolean-expression : := expression== expression |  expression != expression |  expression|  boolean-expression && boolean-expression |  boolean-expression ||boolean-expression |  ! boolean-expression |  (boolean-expression)(here, && has higher precedence than || and both are left associative)expression : := ? |  number |  identifier

[8641] Numbers may be binary, octal, decimal or hexadecimal integers,and use the same syntax as Handel-C. (i.e. 0b . . . for binary numbers,0 . . . for octal numbers, 0x . . . for hex numbers, all other numbersare treated as decimals).

[8642] Identifiers are C-style Identifiers.

[8643] Time Units

[8644] Time units are not explicitly defined in Waveform Analyzer. AnyHandel-C simulation to which the Waveform Analyzer is connected shoulduse the DK1Sync plugin with the clock period for the simulationspecified in an extinst string. When the clock period is entered for atrace or pattern window, the sample rate for the trace or patterns aredetermined in the window relative to the clock period specified for theHandel-C simulation. If the clock period for the trace or pattern is thesame as the clock period specified in the extinst string in the Handel-Cprogram, the trace or pattern may be sampled on every cycle of theHandel-C program. If the clock period for the trace or pattern is twicethe clock period specified in the extinst string in the Handel-Cprogram, the trace or pattern may be sampled on every other cycle of theHandel-C program and so on. It is a matter of convenience to make theclock periods correspond to the clock periods that may be used in thetarget hardware. Preferably, the VCD file reader/writer used by WaveformAnalyzer assumes that the time units used are nanoseconds.

[8645] While various embodiments have been described above, it should beunderstood that they have been presented by way of example only, and notlimitation. Thus, the breadth and scope of a preferred embodiment shouldnot be limited by any of the above-described exemplary embodiments, butshould be defined only in accordance with the following claims and theirequivalents.

What is claimed is:
 1. A method for using a versatile interface,comprising the steps of: (a) writing first computer code in a firstprogramming language; (b) including in the first computer code referenceto second computer code in a second programming language; and (c)simulating the second computer code for use during the execution of thefirst computer code in the first programming language.
 2. A method asrecited in claim 1, wherein the second computer code is simulated by afirst simulator module.
 3. A method as recited in claim 2, wherein thefirst simulator module interfaces a second simulator module.
 4. A methodas recited in claim 3, wherein the first simulator module interfaces thesecond simulator module via a plug-in module.
 5. A method as recited inclaim 1, wherein the reference to the second computer code includes apredetermined command in the first computer code.
 6. A method as recitedin claim 1, wherein the second computer code simulates an externaldevice.
 7. A method as recited in claim 1, wherein the first programminglanguage includes Handel-C.
 8. A method as recited in claim 1, whereinthe second programming language is selected from the group consisting ofEDIF and VDHL.
 9. A computer program product for using a versatileinterface, comprising: (a) first computer code in a first programminglanguage, wherein the first computer code includes reference to secondcomputer code in a second programming language; and (b) computer codefor simulating the second computer code for use during the execution ofthe first computer code in the first programming language.
 10. Acomputer program product as recited in claim 9, wherein the secondcomputer code is simulated by a first simulator module.
 11. A computerprogram product as recited in claim 10, wherein the first simulatormodule interfaces a second simulator module.
 12. A computer programproduct as recited in claim 11, wherein the first simulator moduleinterfaces the second simulator module via a plug-in module.
 13. Acomputer program product as recited in claim 9, wherein the reference tothe second computer code includes a predetermined command in the firstcomputer code.
 14. A computer program product as recited in claim 9,wherein the second computer code simulates an external device.
 15. Acomputer program product as recited in claim 9, wherein the firstprogramming language includes Handel-C.
 16. A computer program productas recited in claim 9, wherein the second programming language isselected from the group consisting of EDIF and VDHL.
 17. A system forusing a versatile interface, comprising: (a) first computer code in afirst programming language, wherein the first computer code includesreference to second computer code in a second programming language; and(b) logic for simulating the second computer code for use during theexecution of the first computer code in the first programming language.18. A system as recited in claim 17, wherein the second computer code issimulated by a first simulator module.
 19. A system as recited in claim18, wherein the first simulator module interfaces a second simulatormodule.
 20. A system as recited in claim 19, wherein the first simulatormodule interfaces the second simulator module via a plug-in module.